aboutsummaryrefslogtreecommitdiff
path: root/src/platform/vulkan
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/vulkan')
-rw-r--r--src/platform/vulkan/vulkan_common.h1
-rw-r--r--src/platform/vulkan/vulkan_device.cpp29
2 files changed, 25 insertions, 5 deletions
diff --git a/src/platform/vulkan/vulkan_common.h b/src/platform/vulkan/vulkan_common.h
index cb86d69..22d389c 100644
--- a/src/platform/vulkan/vulkan_common.h
+++ b/src/platform/vulkan/vulkan_common.h
@@ -343,6 +343,7 @@ namespace Donut::RHI
std::vector<VkDescriptorPool> m_frame_pools; // one per frame in flight
VkDescriptorPool m_imgui_pool = VK_NULL_HANDLE;
+ VkDescriptorPool m_offscreen_pool = VK_NULL_HANDLE; // run_offscreen's own; never a frame's
bool m_imgui = false;
VkCommandListR m_cmds;
diff --git a/src/platform/vulkan/vulkan_device.cpp b/src/platform/vulkan/vulkan_device.cpp
index a4f9ac7..f780f6f 100644
--- a/src/platform/vulkan/vulkan_device.cpp
+++ b/src/platform/vulkan/vulkan_device.cpp
@@ -119,8 +119,24 @@ namespace Donut::RHI
auto VulkanDevice::run_offscreen(const std::function<void(CommandList&)>& record) -> void
{
+ // this gets called mid-frame (the Export button fires from inside ui->draw
+ // while the frame's command buffer is still being recorded), so it has to be
+ // fully self-contained: its own command list AND its own descriptor pool. the
+ // old version reused m_cmds and then freed its buffer, so the in-flight frame
+ // carried on recording into a dangling handle. segfault.
vkDeviceWaitIdle(m_device);
- vkResetDescriptorPool(m_device, m_frame_pools[0], 0); // per-draw sets for this pass
+
+ if (m_offscreen_pool == VK_NULL_HANDLE)
+ {
+ VkDescriptorPoolSize sizes[2] = {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 32 },
+ { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 32 },
+ };
+ VkDescriptorPoolCreateInfo dpci{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ dpci.maxSets = 16; dpci.poolSizeCount = 2; dpci.pPoolSizes = sizes;
+ vkCreateDescriptorPool(m_device, &dpci, nullptr, &m_offscreen_pool);
+ }
+ vkResetDescriptorPool(m_device, m_offscreen_pool, 0); // per-draw sets for this pass
VkCommandBufferAllocateInfo cbai{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
cbai.commandPool = m_command_pool; cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cbai.commandBufferCount = 1;
@@ -128,10 +144,12 @@ namespace Donut::RHI
VkCommandBufferBeginInfo bi{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmd, &bi);
- m_cmds.m_device = m_device; m_cmds.m_cmd = cmd;
- m_cmds.m_swapchain_rp = m_swapchain_rp; m_cmds.m_swapchain_fb = VK_NULL_HANDLE; m_cmds.m_extent = m_extent;
- m_cmds.m_frame_pool = m_frame_pools[0]; m_cmds.m_pipe = nullptr;
- record(m_cmds); // records its own off-screen render pass(es)
+ // a local command list, so the frame's m_cmds is never touched.
+ VkCommandListR ocmds;
+ ocmds.m_device = m_device; ocmds.m_cmd = cmd;
+ ocmds.m_swapchain_rp = m_swapchain_rp; ocmds.m_swapchain_fb = VK_NULL_HANDLE; ocmds.m_extent = m_extent;
+ ocmds.m_frame_pool = m_offscreen_pool; ocmds.m_pipe = nullptr;
+ record(ocmds); // records its own off-screen render pass(es)
vkEndCommandBuffer(cmd);
VkSubmitInfo si{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; si.commandBufferCount = 1; si.pCommandBuffers = &cmd;
@@ -264,6 +282,7 @@ namespace Donut::RHI
if (m_imgui_pool) vkDestroyDescriptorPool(m_device, m_imgui_pool, nullptr);
for (auto p : m_frame_pools) vkDestroyDescriptorPool(m_device, p, nullptr);
m_frame_pools.clear();
+ if (m_offscreen_pool) { vkDestroyDescriptorPool(m_device, m_offscreen_pool, nullptr); m_offscreen_pool = VK_NULL_HANDLE; }
for (auto s : m_render_finished) vkDestroySemaphore(m_device, s, nullptr);
for (auto s : m_image_available) vkDestroySemaphore(m_device, s, nullptr);
for (auto f : m_in_flight) vkDestroyFence(m_device, f, nullptr);