From d7c1ced08d5d78fcb239550404db4e67d4357a19 Mon Sep 17 00:00:00 2001 From: hachem Date: Tue, 22 Sep 2026 06:57:16 +0200 Subject: fix: windows support --- src/platform/vulkan/vulkan_device.cpp | 46 ++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'src/platform/vulkan/vulkan_device.cpp') diff --git a/src/platform/vulkan/vulkan_device.cpp b/src/platform/vulkan/vulkan_device.cpp index f780f6f..54a4a3c 100644 --- a/src/platform/vulkan/vulkan_device.cpp +++ b/src/platform/vulkan/vulkan_device.cpp @@ -1,5 +1,15 @@ #include "vulkan_common.h" +#include +#include + +#if defined(_WIN32) + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include // LoadLibraryExW, for the runtime probe +#endif + #include #include #include @@ -44,7 +54,16 @@ namespace Donut::RHI auto VulkanDevice::create_shader_module(const std::string& path, VkShaderModule& out) const -> bool { auto spv = load_spirv(path); - if (spv.empty()) { DONUT_ERROR("Vulkan RHI: failed to load SPIR-V {}", path); return false; } + if (spv.empty()) + { + // u8string, not string(): msvc's narrow conversion throws on a cwd the + // ANSI code page can't spell, which would turn this log into a crash + std::error_code ec; + const auto cwd = std::filesystem::current_path(ec).u8string(); + DONUT_ERROR("Vulkan RHI: failed to load SPIR-V {} (cwd {}; shaders live in assets/shaders/generated, see tools/compile-shaders.sh)", + path, std::string(cwd.begin(), cwd.end())); + return false; + } VkShaderModuleCreateInfo ci{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; ci.codeSize = spv.size() * 4; ci.pCode = spv.data(); return vkCreateShaderModule(m_device, &ci, nullptr, &out) == VK_SUCCESS; @@ -190,8 +209,15 @@ namespace Donut::RHI vkQueueSubmit(m_graphics_queue, 1, &si, VK_NULL_HANDLE); vkQueueWaitIdle(m_graphics_queue); void* mp = nullptr; vkMapMemory(m_device, mem, 0, sz, 0, &mp); - std::memcpy(out.data(), mp, sz); // RGBA8_UNORM, top-down (top-left origin) + std::memcpy(out.data(), mp, sz); vkUnmapMemory(m_device, mem); + // off-screen targets hold the same rows as on GL: clip-space bottom lands on + // row 0 in both APIs, and the present pass flips it upright. so flip here + // too, exactly like the GL readback, or the export comes out upside down. + const size_t row = (size_t)w * 4; + for (uint32_t y = 0; y < h / 2; ++y) + std::swap_ranges(out.begin() + (std::ptrdiff_t)(y * row), out.begin() + (std::ptrdiff_t)((y + 1) * row), + out.begin() + (std::ptrdiff_t)((h - 1 - y) * row)); vkFreeCommandBuffers(m_device, m_command_pool, 1, &cmd); vkDestroyBuffer(m_device, buf, nullptr); vkFreeMemory(m_device, mem, nullptr); } @@ -227,8 +253,12 @@ namespace Donut::RHI vkQueueSubmit(m_graphics_queue, 1, &si, VK_NULL_HANDLE); vkQueueWaitIdle(m_graphics_queue); void* mp = nullptr; vkMapMemory(m_device, mem, 0, sz, 0, &mp); - std::memcpy(out.data(), mp, sz); // R32G32B32A32_SFLOAT, top-down + std::memcpy(out.data(), mp, sz); // R32G32B32A32_SFLOAT vkUnmapMemory(m_device, mem); + const size_t row = (size_t)w * 4; // same flip as the RGBA8 readback above + for (uint32_t y = 0; y < h / 2; ++y) + std::swap_ranges(out.begin() + (std::ptrdiff_t)(y * row), out.begin() + (std::ptrdiff_t)((y + 1) * row), + out.begin() + (std::ptrdiff_t)((h - 1 - y) * row)); vkFreeCommandBuffers(m_device, m_command_pool, 1, &cmd); vkDestroyBuffer(m_device, buf, nullptr); vkFreeMemory(m_device, mem, nullptr); } @@ -299,6 +329,16 @@ namespace Donut::RHI auto create_vulkan_device() -> Scope { return create_scope(); } + auto vulkan_runtime_available() -> bool + { +#if defined(_WIN32) + // stays loaded on purpose: the delay-load thunks bind to this module later + return LoadLibraryExW(L"vulkan-1.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) != nullptr; +#else + return true; // macOS links the loader directly, and there's no Windows-style delay-load +#endif + } + auto vulkan_prepare_glfw() -> void { #ifdef __APPLE__ -- cgit v1.3