diff options
| author | hachem <im@hachem.wtf> | 2026-09-22 06:57:16 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-22 06:57:16 +0200 |
| commit | d7c1ced08d5d78fcb239550404db4e67d4357a19 (patch) | |
| tree | 9c0e218b096d138075cbf6a48e2562d33a8f94ed /src/platform/vulkan/vulkan_device.cpp | |
| parent | 270eda6f558c972ec86ad0580f1d3d18afc83a94 (diff) | |
Diffstat (limited to 'src/platform/vulkan/vulkan_device.cpp')
| -rw-r--r-- | src/platform/vulkan/vulkan_device.cpp | 46 |
1 files changed, 43 insertions, 3 deletions
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 <algorithm> +#include <filesystem> + +#if defined(_WIN32) + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include <windows.h> // LoadLibraryExW, for the runtime probe +#endif + #include <imgui.h> #include <imgui_impl_glfw.h> #include <imgui_impl_vulkan.h> @@ -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<Device> { return create_scope<VulkanDevice>(); } + 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__ |
