aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/gen_bindings.yml6
-rw-r--r--.github/workflows/main.yml6
-rw-r--r--CHANGELOG.md7
-rw-r--r--sokol_app.h34
-rw-r--r--sokol_gfx.h56
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/CMakePresets.json32
-rw-r--r--tests/test_win.cmd4
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, &region);
_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