Skip to content

Commit d594280

Browse files
committed
Renderer/Vulkan: fix descriptor lifetime issues and swapchain sync
1 parent ef7c0ea commit d594280

File tree

6 files changed

+337
-221
lines changed

6 files changed

+337
-221
lines changed

src/core/renderer/Vulkan/VulkanRenderer.cpp

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ bool VulkanRenderer::initialize()
100100
if (!m_vulkanResources.createBackgroundVertexBuffer(m_vulkanDevice))
101101
return false;
102102

103-
if (!m_vulkanResources.createSyncObjects(m_vulkanDevice.getDevice()))
103+
if (!m_vulkanResources.createSyncObjects(m_vulkanDevice.getDevice(),
104+
static_cast<uint32_t>(m_vulkanSwapchain.getImages().size())))
104105
return false;
105106

106107
if (!createCommandBuffers())
@@ -325,6 +326,13 @@ void VulkanRenderer::resize(uint32_t width, uint32_t height)
325326
m_imagesInFlight.clear();
326327
m_imagesInFlight.resize(m_vulkanSwapchain.getImages().size(), VK_NULL_HANDLE);
327328

329+
if (!m_vulkanResources.recreateRenderFinishedSemaphores(m_vulkanDevice.getDevice(),
330+
static_cast<uint32_t>(m_vulkanSwapchain.getImages().size())))
331+
{
332+
Logger::error("VK: Failed to recreate render-finished semaphores after resize");
333+
return;
334+
}
335+
328336
if (!createCommandBuffers())
329337
{
330338
Logger::error("VK: Failed to recreate command buffers");
@@ -431,6 +439,44 @@ void VulkanRenderer::prepareVertexData()
431439
Logger::debug("VK: Vertex buffer created (host-visible) for animation updates");
432440
}
433441

442+
void VulkanRenderer::writeDescriptorSets()
443+
{
444+
if (m_descriptorSet == VK_NULL_HANDLE || m_uniformBuffer == VK_NULL_HANDLE || m_textureView == VK_NULL_HANDLE)
445+
return;
446+
447+
VkDevice device = m_vulkanDevice.getDevice();
448+
const VkDeviceSize uboSize = 320;
449+
450+
VkDescriptorBufferInfo bufferDescInfo{};
451+
bufferDescInfo.buffer = m_uniformBuffer;
452+
bufferDescInfo.offset = 0;
453+
bufferDescInfo.range = uboSize;
454+
455+
VkDescriptorImageInfo imageDescInfo{};
456+
imageDescInfo.sampler = m_textureSampler;
457+
imageDescInfo.imageView = m_textureView;
458+
imageDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
459+
460+
VkWriteDescriptorSet descriptorWrites[2]{};
461+
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
462+
descriptorWrites[0].dstSet = m_descriptorSet;
463+
descriptorWrites[0].dstBinding = 0;
464+
descriptorWrites[0].dstArrayElement = 0;
465+
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
466+
descriptorWrites[0].descriptorCount = 1;
467+
descriptorWrites[0].pBufferInfo = &bufferDescInfo;
468+
469+
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
470+
descriptorWrites[1].dstSet = m_descriptorSet;
471+
descriptorWrites[1].dstBinding = 1;
472+
descriptorWrites[1].dstArrayElement = 0;
473+
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
474+
descriptorWrites[1].descriptorCount = 1;
475+
descriptorWrites[1].pImageInfo = &imageDescInfo;
476+
477+
vkUpdateDescriptorSets(device, 2, descriptorWrites, 0, nullptr);
478+
}
479+
434480
void VulkanRenderer::updateUniformBuffer()
435481
{
436482
VkDevice device = m_vulkanDevice.getDevice();
@@ -603,38 +649,7 @@ void VulkanRenderer::updateUniformBuffer()
603649
descriptorWrites[1].descriptorCount = 1;
604650
descriptorWrites[1].pImageInfo = &imageDescInfo;
605651

606-
vkUpdateDescriptorSets(device, 2, descriptorWrites, 0, nullptr);
607-
}
608-
else if (m_descriptorSet != VK_NULL_HANDLE && m_textureView != VK_NULL_HANDLE)
609-
{
610-
VkDescriptorBufferInfo bufferDescInfo{};
611-
bufferDescInfo.buffer = m_uniformBuffer;
612-
bufferDescInfo.offset = 0;
613-
bufferDescInfo.range = uboSize;
614-
615-
VkDescriptorImageInfo imageDescInfo{};
616-
imageDescInfo.sampler = m_textureSampler;
617-
imageDescInfo.imageView = m_textureView;
618-
imageDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
619-
620-
VkWriteDescriptorSet descriptorWrites[2]{};
621-
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
622-
descriptorWrites[0].dstSet = m_descriptorSet;
623-
descriptorWrites[0].dstBinding = 0;
624-
descriptorWrites[0].dstArrayElement = 0;
625-
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
626-
descriptorWrites[0].descriptorCount = 1;
627-
descriptorWrites[0].pBufferInfo = &bufferDescInfo;
628-
629-
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
630-
descriptorWrites[1].dstSet = m_descriptorSet;
631-
descriptorWrites[1].dstBinding = 1;
632-
descriptorWrites[1].dstArrayElement = 0;
633-
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
634-
descriptorWrites[1].descriptorCount = 1;
635-
descriptorWrites[1].pImageInfo = &imageDescInfo;
636-
637-
vkUpdateDescriptorSets(device, 2, descriptorWrites, 0, nullptr);
652+
writeDescriptorSets();
638653
}
639654

640655
void* data;
@@ -773,6 +788,7 @@ bool VulkanRenderer::uploadTexture()
773788
}
774789
Logger::debug("VK: Texture image view created, calling updateUniformBuffer");
775790

791+
writeDescriptorSets();
776792
updateUniformBuffer();
777793

778794
vkDestroyBuffer(device, stagingBuffer, nullptr);
@@ -874,7 +890,10 @@ bool VulkanRenderer::createCommandBuffers()
874890
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
875891
renderPassInfo.pClearValues = clearValues.data();
876892

877-
vkCmdBeginRenderPass(m_commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
893+
VkSubpassBeginInfo subpassBegin{};
894+
subpassBegin.sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO;
895+
subpassBegin.contents = VK_SUBPASS_CONTENTS_INLINE;
896+
vkCmdBeginRenderPass2(m_commandBuffers[i], &renderPassInfo, &subpassBegin);
878897

879898
VkBuffer bgBuffer = m_vulkanResources.getBackgroundVertexBuffer();
880899
if (m_background.shouldRender && m_vulkanPipeline.getBackgroundPipeline() != VK_NULL_HANDLE && bgBuffer != VK_NULL_HANDLE)
@@ -919,7 +938,9 @@ bool VulkanRenderer::createCommandBuffers()
919938
vkCmdDraw(m_commandBuffers[i], m_vertexCount, 1, 0, 0);
920939
}
921940

922-
vkCmdEndRenderPass(m_commandBuffers[i]);
941+
VkSubpassEndInfo subpassEnd{};
942+
subpassEnd.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
943+
vkCmdEndRenderPass2(m_commandBuffers[i], &subpassEnd);
923944

924945
if (vkEndCommandBuffer(m_commandBuffers[i]) != VK_SUCCESS)
925946
{
@@ -948,7 +969,6 @@ void VulkanRenderer::submitFrame()
948969

949970
VkFence fence = m_vulkanResources.getInFlightFence(m_currentFrame);
950971
VkSemaphore imageAvailable = m_vulkanResources.getImageAvailableSemaphore(m_currentFrame);
951-
VkSemaphore renderFinished = m_vulkanResources.getRenderFinishedSemaphore(m_currentFrame);
952972
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
953973

954974
uint32_t imageIndex;
@@ -966,6 +986,8 @@ void VulkanRenderer::submitFrame()
966986
return;
967987
}
968988

989+
VkSemaphore renderFinished = m_vulkanResources.getRenderFinishedSemaphore(imageIndex);
990+
969991
if (m_imagesInFlight[imageIndex] != VK_NULL_HANDLE)
970992
{
971993
vkWaitForFences(device, 1, &m_imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
@@ -1023,13 +1045,31 @@ void VulkanRenderer::submitFrame()
10231045

10241046
void VulkanRenderer::setVSync(bool enabled)
10251047
{
1026-
if (m_vulkanDevice.getDevice() != VK_NULL_HANDLE)
1027-
{
1028-
m_vulkanSwapchain.setVSync(m_vulkanDevice, enabled);
1048+
if (m_vulkanDevice.getDevice() == VK_NULL_HANDLE || !m_initialized)
1049+
return;
10291050

1030-
if (m_config)
1051+
VkDevice device = m_vulkanDevice.getDevice();
1052+
if (m_vulkanSwapchain.setVSync(m_vulkanDevice, enabled))
1053+
{
1054+
vkDeviceWaitIdle(device);
1055+
m_imagesInFlight.clear();
1056+
m_imagesInFlight.resize(m_vulkanSwapchain.getImages().size(), VK_NULL_HANDLE);
1057+
if (!m_vulkanResources.recreateRenderFinishedSemaphores(device,
1058+
static_cast<uint32_t>(m_vulkanSwapchain.getImages().size())))
10311059
{
1032-
m_config->setVSync(enabled);
1060+
Logger::error("VK: Failed to recreate render-finished semaphores after VSync change");
10331061
}
1062+
if (!m_commandBuffers.empty())
1063+
{
1064+
vkFreeCommandBuffers(device, m_vulkanResources.getCommandPool(),
1065+
static_cast<uint32_t>(m_commandBuffers.size()), m_commandBuffers.data());
1066+
m_commandBuffers.clear();
1067+
}
1068+
if (!createCommandBuffers())
1069+
Logger::error("VK: Failed to recreate command buffers after VSync change");
1070+
m_iconChanged = true;
10341071
}
1072+
1073+
if (m_config)
1074+
m_config->setVSync(enabled);
10351075
}

src/core/renderer/Vulkan/VulkanRenderer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class VulkanRenderer : public Renderer
105105

106106
bool createCommandBuffers();
107107
bool uploadTexture();
108+
void writeDescriptorSets();
108109
void updateBackgroundVertexData();
109110

110111
void prepareVertexData();

src/core/renderer/Vulkan/VulkanResources.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,37 @@ bool VulkanResources::createCommandPool(VkDevice device, uint32_t queueFamily)
2828
return true;
2929
}
3030

31-
bool VulkanResources::createSyncObjects(VkDevice device)
31+
bool VulkanResources::recreateRenderFinishedSemaphores(VkDevice device, uint32_t swapchainImageCount)
32+
{
33+
for (VkSemaphore s : m_renderFinishedSemaphores)
34+
{
35+
if (s != VK_NULL_HANDLE)
36+
vkDestroySemaphore(device, s, nullptr);
37+
}
38+
m_renderFinishedSemaphores.clear();
39+
m_renderFinishedSemaphores.resize(swapchainImageCount);
40+
41+
VkSemaphoreCreateInfo semaphoreInfo{};
42+
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
43+
44+
for (uint32_t i = 0; i < swapchainImageCount; ++i)
45+
{
46+
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS)
47+
{
48+
Logger::error("VK: Failed to create render-finished semaphore {}", i);
49+
for (uint32_t j = 0; j < i; ++j)
50+
{
51+
vkDestroySemaphore(device, m_renderFinishedSemaphores[j], nullptr);
52+
m_renderFinishedSemaphores[j] = VK_NULL_HANDLE;
53+
}
54+
m_renderFinishedSemaphores.clear();
55+
return false;
56+
}
57+
}
58+
return true;
59+
}
60+
61+
bool VulkanResources::createSyncObjects(VkDevice device, uint32_t swapchainImageCount)
3262
{
3363
VkSemaphoreCreateInfo semaphoreInfo{};
3464
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -40,14 +70,16 @@ bool VulkanResources::createSyncObjects(VkDevice device)
4070
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
4171
{
4272
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS ||
43-
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS ||
4473
vkCreateFence(device, &fenceInfo, nullptr, &m_inFlightFences[i]) != VK_SUCCESS)
4574
{
4675
Logger::error("VK: Failed to create synchronization objects for frame {}", i);
4776
return false;
4877
}
4978
}
5079

80+
if (!recreateRenderFinishedSemaphores(device, swapchainImageCount))
81+
return false;
82+
5183
VkFenceCreateInfo singleTimeFenceInfo{};
5284
singleTimeFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
5385
singleTimeFenceInfo.flags = 0; // Not signaled
@@ -72,18 +104,20 @@ void VulkanResources::destroy(VkDevice device)
72104
m_singleTimeFence = VK_NULL_HANDLE;
73105
}
74106

107+
for (VkSemaphore s : m_renderFinishedSemaphores)
108+
{
109+
if (s != VK_NULL_HANDLE)
110+
vkDestroySemaphore(device, s, nullptr);
111+
}
112+
m_renderFinishedSemaphores.clear();
113+
75114
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
76115
{
77116
if (m_inFlightFences[i] != VK_NULL_HANDLE)
78117
{
79118
vkDestroyFence(device, m_inFlightFences[i], nullptr);
80119
m_inFlightFences[i] = VK_NULL_HANDLE;
81120
}
82-
if (m_renderFinishedSemaphores[i] != VK_NULL_HANDLE)
83-
{
84-
vkDestroySemaphore(device, m_renderFinishedSemaphores[i], nullptr);
85-
m_renderFinishedSemaphores[i] = VK_NULL_HANDLE;
86-
}
87121
if (m_imageAvailableSemaphores[i] != VK_NULL_HANDLE)
88122
{
89123
vkDestroySemaphore(device, m_imageAvailableSemaphores[i], nullptr);

src/core/renderer/Vulkan/VulkanResources.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vulkan/vulkan.h>
77
#include <cstdint>
88
#include <array>
9+
#include <vector>
910
#include "Logger.h"
1011

1112
class VulkanDevice;
@@ -44,7 +45,8 @@ class VulkanResources
4445
VulkanResources& operator=(const VulkanResources&) = delete;
4546

4647
bool createCommandPool(VkDevice device, uint32_t queueFamily);
47-
bool createSyncObjects(VkDevice device);
48+
bool createSyncObjects(VkDevice device, uint32_t swapchainImageCount);
49+
bool recreateRenderFinishedSemaphores(VkDevice device, uint32_t swapchainImageCount);
4850
void destroy(VkDevice device);
4951

5052
VkCommandBuffer beginSingleTimeCommands(VkDevice device);
@@ -64,14 +66,14 @@ class VulkanResources
6466

6567
VkCommandPool getCommandPool() const { return m_commandPool; }
6668
VkSemaphore getImageAvailableSemaphore(uint32_t frameIndex) const { return m_imageAvailableSemaphores[frameIndex]; }
67-
VkSemaphore getRenderFinishedSemaphore(uint32_t frameIndex) const { return m_renderFinishedSemaphores[frameIndex]; }
69+
VkSemaphore getRenderFinishedSemaphore(uint32_t imageIndex) const { return m_renderFinishedSemaphores[imageIndex]; }
6870
VkFence getInFlightFence(uint32_t frameIndex) const { return m_inFlightFences[frameIndex]; }
6971
VkBuffer getBackgroundVertexBuffer() const { return m_bgVertexBuffer; }
7072

7173
private:
7274
VkCommandPool m_commandPool = VK_NULL_HANDLE;
7375
std::array<VkSemaphore, MAX_FRAMES_IN_FLIGHT> m_imageAvailableSemaphores{};
74-
std::array<VkSemaphore, MAX_FRAMES_IN_FLIGHT> m_renderFinishedSemaphores{};
76+
std::vector<VkSemaphore> m_renderFinishedSemaphores;
7577
std::array<VkFence, MAX_FRAMES_IN_FLIGHT> m_inFlightFences{};
7678
VkFence m_singleTimeFence = VK_NULL_HANDLE;
7779

0 commit comments

Comments
 (0)