aboutsummaryrefslogtreecommitdiff
path: root/src/platform/vulkan/vulkan_device.cpp
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-22 06:57:16 +0200
committerhachem <im@hachem.wtf>2026-09-22 06:57:16 +0200
commitd7c1ced08d5d78fcb239550404db4e67d4357a19 (patch)
tree9c0e218b096d138075cbf6a48e2562d33a8f94ed /src/platform/vulkan/vulkan_device.cpp
parent270eda6f558c972ec86ad0580f1d3d18afc83a94 (diff)
fix: windows supportHEADmain
Diffstat (limited to 'src/platform/vulkan/vulkan_device.cpp')
-rw-r--r--src/platform/vulkan/vulkan_device.cpp46
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__