diff options
| author | Andre Weissflog <floooh@gmail.com> | 2026-01-19 19:19:18 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-19 19:19:18 +0100 |
| commit | b7fd45d2e361489005dfe15fd07f7016b8661afb (patch) | |
| tree | 4b1dc5a5e66f1dcb78af84828b26c9807580449e | |
| parent | 486d19da7c0e4fd20274ac5ec4e2f0fee358830c (diff) | |
| parent | 733bfca96b074814f8148f41f7764aec70f43d77 (diff) | |
Merge pull request #1417 from floooh/vulkan-windows
Enable experimental vulkan backend on Windows
| -rw-r--r-- | .github/workflows/gen_bindings.yml | 6 | ||||
| -rw-r--r-- | .github/workflows/main.yml | 6 | ||||
| -rw-r--r-- | CHANGELOG.md | 7 | ||||
| -rw-r--r-- | sokol_app.h | 34 | ||||
| -rw-r--r-- | sokol_gfx.h | 56 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | tests/CMakePresets.json | 32 | ||||
| -rw-r--r-- | tests/test_win.cmd | 4 |
8 files changed, 129 insertions, 23 deletions
diff --git a/.github/workflows/gen_bindings.yml b/.github/workflows/gen_bindings.yml index ffe6de65..f9a0a68d 100644 --- a/.github/workflows/gen_bindings.yml +++ b/.github/workflows/gen_bindings.yml @@ -7,6 +7,12 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@main + - name: prepare vulkan sdk + uses: humbletim/setup-vulkan-sdk@main + with: + vulkan-query-version: 1.4.335.0 + vulkan-components: Vulkan-Headers, Vulkan-Loader + vulkan-use-cache: true - name: test_win run: | cd tests diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7da3c027..073ad6c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,12 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@main + - name: prepare vulkan sdk + uses: humbletim/setup-vulkan-sdk@main + with: + vulkan-query-version: 1.4.335.0 + vulkan-components: Vulkan-Headers, Vulkan-Loader + vulkan-use-cache: true - name: test_win run: | cd tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f15a136..d885b503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ per-multiple-render-target color write masks on GLES3.2. Many thanks to @luigi-rosso for the PR! +- sokol_app.h: Added Windows support for the experimental Vulkan backend + (still only tested on an Intel Meteor Lake integrated GPU). The other good news + is that RenderDoc works with the sokol-gfx vulkan backend on Windows (it didn't on + Linux). + + PR: https://github.com/floooh/sokol/pull/1417 + ### 18-Jan-2026 Happy New Year! diff --git a/sokol_app.h b/sokol_app.h index 99f25d11..5082d23c 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -23,6 +23,7 @@ #define SOKOL_D3D11 #define SOKOL_METAL #define SOKOL_WGPU + #define SOKOL_VULKAN #define SOKOL_NOAPI Optionally provide the following defines with your own implementations: @@ -79,11 +80,17 @@ - with SOKOL_GLCORE: GL - with SOKOL_GLES3: GLESv2 - with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn) + - with SOKOL_VULKAN: vulkan - with EGL: EGL - on Android: GLESv3, EGL, log, android - on Windows: - with MSVC or Clang: library dependencies are defined via `#pragma comment` - with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn) + - with SOKOL_VULKAN: + - install the Vulkan SDK + - set a header search path to $VULKAN_SDK/Include + - set a library search path to $VULKAN_SDK/Lib + - link with vulkan-1.lib - with MINGW/MSYS2 gcc: - compile with '-mwin32' so that _WIN32 is defined - link with the following libs: -lkernel32 -luser32 -lshell32 @@ -93,6 +100,11 @@ On Linux, you also need to use the -pthread compiler and linker option, otherwise weird things will happen, see here for details: https://github.com/floooh/sokol/issues/376 + For Linux+Vulkan install the following packages (or equivalents): + - libvulkan-dev + - vulkan-validationlayers + - vulkan-tools + On macOS and iOS, the implementation must be compiled as Objective-C. On Emscripten: @@ -2307,8 +2319,12 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #elif defined(_WIN32) // Windows (D3D11 or GL) #define _SAPP_WIN32 (1) - #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) && !defined(SOKOL_NOAPI) - #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE, SOKOL_WGPU or SOKOL_NOAPI") + #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) && !defined(SOKOL_VULKAN) && !defined(SOKOL_NOAPI) + #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE, SOKOL_WGPU, SOKOL_VULKAN or SOKOL_NOAPI") + #endif + #if defined(SOKOL_VULKAN) + #define VK_USE_PLATFORM_WIN32_KHR + #include <vulkan/vulkan.h> #endif #elif defined(__ANDROID__) // Android @@ -4291,6 +4307,8 @@ _SOKOL_PRIVATE void _sapp_vk_create_instance(void) { ext_names[ext_count++] = VK_KHR_SURFACE_EXTENSION_NAME; #if defined(VK_USE_PLATFORM_XLIB_KHR) ext_names[ext_count++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; + #elif defined(VK_USE_PLATFORM_WIN32_KHR) + ext_names[ext_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; #endif SOKOL_ASSERT(ext_count <= 32); @@ -4517,6 +4535,12 @@ _SOKOL_PRIVATE void _sapp_vk_create_surface(void) { xlib_info.dpy = _sapp.x11.display; xlib_info.window = _sapp.x11.window; res = vkCreateXlibSurfaceKHR(_sapp.vk.instance, &xlib_info, 0, &_sapp.vk.surface); + #elif defined(_SAPP_WIN32) + _SAPP_STRUCT(VkWin32SurfaceCreateInfoKHR, win32_info); + win32_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + win32_info.hinstance = GetModuleHandleW(NULL); + win32_info.hwnd = _sapp.win32.hwnd; + res = vkCreateWin32SurfaceKHR(_sapp.vk.instance, &win32_info, 0, &_sapp.vk.surface); #else #error "sokol_app.h: unsupported Vulkan platform" #endif @@ -9076,6 +9100,8 @@ _SOKOL_PRIVATE void _sapp_win32_timing_measure(void) { _SOKOL_PRIVATE void _sapp_win32_frame(bool from_winproc) { #if defined(SOKOL_WGPU) _sapp_wgpu_frame(); + #elif defined(SOKOL_VULKAN) + _sapp_vk_frame(); #else _sapp_frame(); #endif @@ -9693,6 +9719,8 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_wgl_create_context(); #elif defined(SOKOL_WGPU) _sapp_wgpu_init(); + #elif defined(SOKOL_VULKAN) + _sapp_vk_init(); #endif _sapp.valid = true; @@ -9741,6 +9769,8 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_wgl_shutdown(); #elif defined(SOKOL_WGPU) _sapp_wgpu_discard(); + #elif defined(SOKOL_VULKAN) + _sapp_vk_discard(); #endif _sapp_win32_destroy_window(); _sapp_win32_destroy_icons(); diff --git a/sokol_gfx.h b/sokol_gfx.h index 524de711..1bb40043 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -70,13 +70,27 @@ - on iOS with GL: OpenGLES - on Linux with EGL: GL or GLESv2 - on Linux with GLX: GL + - on Linux with Vulkan: vulkan - on Android: GLESv3, log, android - - on Windows with the MSVC or Clang toolchains: no action needed, libs are defined in-source via pragma-comment-lib - - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined - - with the D3D11 backend: -ld3d11 + - on Windows: + - with Vulkan: link with vulkan-1 (this is explicit in case you want to + use your own Vulkan loader library) + - with D3D11: + - on MSVC or Clang: no action needed, libs are defined in-source via pragma-comment-lib + - on MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined and link with -ld3d11 + - with GL: no linking needed since sokol_gfx.h comes with its own GL loader on Windows On macOS and iOS, the implementation must be compiled as Objective-C. + For Linux+Vulkan install the following packages (or equivalents): + - libvulkan-dev + - vulkan-validationlayers + - vulkan-tools + + For Windows+Vulkan install the Vulkan SDK and in your build system: + - add a header search path to $ENV{VULKAN_SDK}/Include + - add a link search path to $ENV{VULKAN_SDK}/Env + On Emscripten: - for WebGL2: add the linker option `-s USE_WEBGL2=1` - for WebGPU: compile and link with `--use-port=emdawnwebgpu` @@ -19126,7 +19140,7 @@ _SOKOL_PRIVATE VkDeviceMemory _sg_vk_mem_alloc_device_memory(_sg_vk_memtype_t me VkDeviceMemory vk_dev_mem = 0; VkResult res = vkAllocateMemory(_sg.vk.dev, &alloc_info, 0, &vk_dev_mem); _sg_stats_inc(vk.num_allocate_memory); - _sg_stats_add(vk.size_allocate_memory, mem_reqs->size); + _sg_stats_add(vk.size_allocate_memory, (uint32_t)mem_reqs->size); if (res != VK_SUCCESS) { _SG_ERROR(VULKAN_ALLOCATE_MEMORY_FAILED); return 0; @@ -19536,7 +19550,7 @@ _SOKOL_PRIVATE void _sg_vk_staging_copy_buffer_data(_sg_buffer_t* buf, const sg_ bytes_remaining = 0; } region.size = bytes_to_copy; - _sg_vk_staging_map_memcpy_unmap(dst_mem, src_ptr, bytes_to_copy); + _sg_vk_staging_map_memcpy_unmap(dst_mem, src_ptr, (uint32_t)bytes_to_copy); VkCommandBuffer cmd_buf = _sg_vk_staging_copy_begin(); vkCmdCopyBuffer(cmd_buf, src_buf, dst_buf, 1, ®ion); _sg_stats_inc(vk.num_cmd_copy_buffer); @@ -19665,7 +19679,7 @@ _SOKOL_PRIVATE void _sg_vk_staging_stream_buffer_data(_sg_buffer_t* buf, const s SOKOL_ASSERT(src_data && src_data->ptr && (src_data->size > 0)); SOKOL_ASSERT((src_data->size + dst_offset) <= (size_t)buf->cmn.size); - const uint32_t src_offset = _sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_data->ptr, src_data->size); + const uint32_t src_offset = (uint32_t)_sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_data->ptr, (uint32_t)src_data->size); if (src_offset == _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT) { _SG_ERROR(VULKAN_STAGING_STREAM_BUFFER_OVERFLOW); return; @@ -19700,7 +19714,7 @@ _SOKOL_PRIVATE void _sg_vk_staging_stream_image_data(_sg_image_t* img, const sg_ const sg_range* src_mip = &src_data->mip_levels[mip_index]; SOKOL_ASSERT(src_mip->ptr); SOKOL_ASSERT(src_mip->size > 0); - const uint32_t src_offset = _sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_mip->ptr, src_mip->size); + const uint32_t src_offset = (uint32_t)_sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_mip->ptr, (uint32_t)src_mip->size); if (src_offset == _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT) { _SG_ERROR(VULKAN_STAGING_STREAM_BUFFER_OVERFLOW); _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); @@ -19731,7 +19745,7 @@ _SOKOL_PRIVATE void _sg_vk_uniform_init(void) { SOKOL_ASSERT(_sg.desc.uniform_buffer_size > 0); _sg_vk_shared_buffer_init(&_sg.vk.uniform, (uint32_t)_sg.desc.uniform_buffer_size, - _sg.vk.dev_props.properties.limits.minUniformBufferOffsetAlignment, + (uint32_t)_sg.vk.dev_props.properties.limits.minUniformBufferOffsetAlignment, _SG_VK_MEMTYPE_UNIFORMS, "shared-uniform-buffer"); for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { @@ -19766,7 +19780,7 @@ _SOKOL_PRIVATE void _sg_vk_uniform_before_submit(void) { // called form _sg_vk_apply_uniforms, returns offset of data snippet into uniform buffer _SOKOL_PRIVATE uint32_t _sg_vk_uniform_copy(const sg_range* data) { SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - return _sg_vk_shared_buffer_memcpy(&_sg.vk.uniform, data->ptr, data->size); + return (uint32_t)_sg_vk_shared_buffer_memcpy(&_sg.vk.uniform, data->ptr, (uint32_t)data->size); } // resource binding system @@ -19774,7 +19788,7 @@ _SOKOL_PRIVATE void _sg_vk_bind_init(void) { SOKOL_ASSERT(_sg.desc.vulkan.descriptor_buffer_size > 0); _sg_vk_shared_buffer_init(&_sg.vk.bind, (uint32_t)_sg.desc.vulkan.descriptor_buffer_size, - _sg.vk.descriptor_buffer_props.descriptorBufferOffsetAlignment, + (uint32_t)_sg.vk.descriptor_buffer_props.descriptorBufferOffsetAlignment, _SG_VK_MEMTYPE_DESCRIPTORS, "shared-descriptor-buffer"); } @@ -19816,12 +19830,12 @@ _SOKOL_PRIVATE bool _sg_vk_bind_view_smp_descriptor_set(VkCommandBuffer cmd_buf, // nothing to bind return true; } - const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, dset_size); + const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, (uint32_t)dset_size); if (_sg.vk.bind.overflown) { _SG_ERROR(VULKAN_DESCRIPTOR_BUFFER_OVERFLOW); return false; } - _sg_stats_add(vk.size_descriptor_buffer_writes, dset_size); + _sg_stats_add(vk.size_descriptor_buffer_writes, (uint32_t)dset_size); uint8_t* dbuf_ptr = _sg_vk_shared_buffer_ptr(&_sg.vk.bind, dbuf_offset); // copy pre-recorded descriptor data into descriptor buffer @@ -19871,12 +19885,12 @@ _SOKOL_PRIVATE bool _sg_vk_bind_uniform_descriptor_set(VkCommandBuffer cmd_buf) const _sg_shader_t* shd = _sg_shader_ref_ptr(&pip->cmn.shader); // get next pointer in descriptor buffer - const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, shd->vk.ub_dset_size); + const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, (uint32_t)shd->vk.ub_dset_size); if (_sg.vk.bind.overflown) { _SG_ERROR(VULKAN_DESCRIPTOR_BUFFER_OVERFLOW); return false; } - _sg_stats_add(vk.size_descriptor_buffer_writes, shd->vk.ub_dset_size); + _sg_stats_add(vk.size_descriptor_buffer_writes, (uint32_t)shd->vk.ub_dset_size); uint8_t* dbuf_ptr = _sg_vk_shared_buffer_ptr(&_sg.vk.bind, dbuf_offset); // update descriptor buffer @@ -20542,7 +20556,7 @@ _SOKOL_PRIVATE void _sg_vk_acquire_frame_command_buffers(void) { _sg.cur_pass.valid = false; return; } - VkResult res = vkResetFences(_sg.vk.dev, 1, &_sg.vk.frame.slot[_sg.vk.frame_slot].fence); + res = vkResetFences(_sg.vk.dev, 1, &_sg.vk.frame.slot[_sg.vk.frame_slot].fence); SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); _sg_vk_delete_queue_collect(); @@ -20952,7 +20966,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_vk_create_shader(_sg_shader_t* shd, const s VkResult res; _SG_STRUCT(VkDescriptorSetLayoutBinding, dsl_entries[_SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_ENTRIES]); _SG_STRUCT(VkDescriptorSetLayoutCreateInfo, dsl_create_info); - size_t dsl_index = 0; + uint32_t dsl_index = 0; for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { if (shd->cmn.uniform_blocks[i].stage == SG_SHADERSTAGE_NONE) { continue; @@ -20984,7 +20998,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_vk_create_shader(_sg_shader_t* shd, const s const uint8_t vk_bnd = shd->vk.ub_set0_bnd_n[i]; VkDeviceSize dset_offset = 0; _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.ub_dsl, vk_bnd, &dset_offset); - shd->vk.ub_dset_offsets[i] = dset_offset; + shd->vk.ub_dset_offsets[i] = (uint16_t)dset_offset; } _sg_clear(dsl_entries, sizeof(dsl_entries)); @@ -21045,7 +21059,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_vk_create_shader(_sg_shader_t* shd, const s const uint8_t vk_bnd = shd->vk.view_set1_bnd_n[i]; VkDeviceSize dset_offset = 0; _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.view_smp_dsl, vk_bnd, &dset_offset); - shd->vk.view_dset_offsets[i] = dset_offset; + shd->vk.view_dset_offsets[i] = (uint16_t)dset_offset; } for (size_t i = 0; i < SG_MAX_SAMPLER_BINDSLOTS; i++) { if (shd->cmn.samplers[i].stage == SG_SHADERSTAGE_NONE) { @@ -21054,7 +21068,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_vk_create_shader(_sg_shader_t* shd, const s const uint8_t vk_bnd = shd->vk.smp_set1_bnd_n[i]; VkDeviceSize dset_offset = 0; _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.view_smp_dsl, vk_bnd, &dset_offset); - shd->vk.smp_dset_offsets[i] = dset_offset; + shd->vk.smp_dset_offsets[i] = (uint16_t)dset_offset; } VkDescriptorSetLayout set_layouts[_SG_VK_NUM_DESCRIPTORSETS] = { @@ -21542,7 +21556,7 @@ _SOKOL_PRIVATE void _sg_vk_begin_render_pass(VkCommandBuffer cmd_buf, const sg_p vkCmdBeginRendering(cmd_buf, &render_info); _SG_STRUCT(VkViewport, vp); - vp.y = _sg.cur_pass.dim.height; + vp.y = (float)_sg.cur_pass.dim.height; vp.width = (float)_sg.cur_pass.dim.width; vp.height = (float)-_sg.cur_pass.dim.height; vp.maxDepth = 1.0f; @@ -21609,7 +21623,7 @@ _SOKOL_PRIVATE bool _sg_vk_apply_bindings(_sg_bindings_ptrs_t* bnd) { // FIXME: could do this in a single call if buffer bindings are guaranteed // to be continuous (currently that's not checked anywhere), or alternative // via nullDescriptor robustness feature (which apparently may have performance downsides) - for (size_t i = 0; i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) { + for (uint32_t i = 0; i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) { if (bnd->vbs[i]) { VkBuffer vk_buf = bnd->vbs[i]->vk.buf; VkDeviceSize vk_offset = (VkDeviceSize)bnd->vb_offsets[i]; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 084900cd..69133da5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -117,6 +117,9 @@ elseif (OSX_MACOS) endif() elseif (WINDOWS) set(exe_type WIN32) + if (SOKOL_BACKEND STREQUAL SOKOL_VULKAN) + set(system_libs ${system_libs} vulkan-1) + endif() endif() macro(configure_common target) @@ -128,6 +131,10 @@ macro(configure_common target) target_link_libraries(${target} PRIVATE ${system_libs}) target_include_directories(${target} PRIVATE ../.. ../../util) target_include_directories(${target} PRIVATE ../ext) + if (WINDOWS AND SOKOL_BACKEND STREQUAL SOKOL_VULKAN) + target_include_directories(${target} PUBLIC $ENV{VULKAN_SDK}/Include) + target_link_directories(${target} PUBLIC $ENV{VULKAN_SDK}/Lib) + endif() endmacro() macro(configure_osx_properties target) diff --git a/tests/CMakePresets.json b/tests/CMakePresets.json index d8a41850..2f9a64c7 100644 --- a/tests/CMakePresets.json +++ b/tests/CMakePresets.json @@ -468,6 +468,28 @@ } }, { + "name": "win_vk", + "binaryDir": "build/win_vk", + "cacheVariables": { + "SOKOL_BACKEND": "SOKOL_VULKAN" + } + }, + { + "name": "win_vk_analyze", + "generator": "Ninja", + "binaryDir": "build/win_vk_analyze", + "cacheVariables": { + "SOKOL_BACKEND": "SOKOL_VULKAN", + "CMAKE_BUILD_TYPE": "Debug", + "USE_ANALYZER": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { "name": "win_gl", "binaryDir": "build/win_gl", "cacheVariables": { @@ -694,6 +716,16 @@ "configurePreset": "android_release" }, { + "name": "win_vk_debug", + "configurePreset": "win_vk", + "configuration": "Debug" + }, + { + "name": "win_vk_release", + "configurePreset": "win_vk", + "configuration": "Release" + }, + { "name": "win_gl_debug", "configurePreset": "win_gl", "configuration": "Debug" diff --git a/tests/test_win.cmd b/tests/test_win.cmd index d4c16a7e..91691773 100644 --- a/tests/test_win.cmd +++ b/tests/test_win.cmd @@ -1,3 +1,7 @@ +cmake --preset win_vk || exit /b 10 +cmake --build --preset win_vk_debug || exit /b 10 +cmake --build --preset win_vk_release || exit /b 10 + cmake --preset win_gl || exit /b 10 cmake --build --preset win_gl_debug || exit /b 10 cmake --build --preset win_gl_release || exit /b 10 |