13void Check(VkResult result,
const char *what)
15 if (result != VK_SUCCESS)
17 throw std::runtime_error(std::string(
"vk renderer: ") + what +
" failed (VkResult=" +
18 std::to_string(
static_cast<int>(result)) +
")");
26 AllocateCommandBuffers();
35 if (m_imageAvailable[i]) vkDestroySemaphore(device, m_imageAvailable[i],
nullptr);
36 if (m_renderFinished[i]) vkDestroySemaphore(device, m_renderFinished[i],
nullptr);
37 if (m_inFlight[i]) vkDestroyFence(device, m_inFlight[i],
nullptr);
41 vkDestroyCommandPool(device, m_cmdPool,
nullptr);
50void Renderer::CreateCommandPool()
52 VkCommandPoolCreateInfo info{};
53 info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
54 info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
56 Check(vkCreateCommandPool(m_ctx.
GetDevice(), &info,
nullptr, &m_cmdPool),
57 "vkCreateCommandPool");
60void Renderer::AllocateCommandBuffers()
62 VkCommandBufferAllocateInfo info{};
63 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
64 info.commandPool = m_cmdPool;
65 info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
67 Check(vkAllocateCommandBuffers(m_ctx.
GetDevice(), &info, m_cmdBuffers.data()),
68 "vkAllocateCommandBuffers");
71void Renderer::CreateSyncObjects()
73 VkSemaphoreCreateInfo sem{};
74 sem.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
75 VkFenceCreateInfo fen{};
76 fen.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
77 fen.flags = VK_FENCE_CREATE_SIGNALED_BIT;
82 Check(vkCreateSemaphore(device, &sem,
nullptr, &m_imageAvailable[i]),
83 "vkCreateSemaphore (imageAvailable)");
84 Check(vkCreateSemaphore(device, &sem,
nullptr, &m_renderFinished[i]),
85 "vkCreateSemaphore (renderFinished)");
86 Check(vkCreateFence(device, &fen,
nullptr, &m_inFlight[i]),
91void Renderer::RecordCommandBuffer(VkCommandBuffer cb, uint32_t imageIndex,
92 float r,
float g,
float b)
94 VkCommandBufferBeginInfo begin{};
95 begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
96 Check(vkBeginCommandBuffer(cb, &begin),
"vkBeginCommandBuffer");
99 clear.color = { { r, g, b, 1.0f } };
101 VkRenderPassBeginInfo rp{};
102 rp.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
105 rp.renderArea.offset = { 0, 0 };
106 rp.renderArea.extent = m_swap.
GetExtent();
107 rp.clearValueCount = 1;
108 rp.pClearValues = &clear;
110 vkCmdBeginRenderPass(cb, &rp, VK_SUBPASS_CONTENTS_INLINE);
113 vkCmdEndRenderPass(cb);
115 Check(vkEndCommandBuffer(cb),
"vkEndCommandBuffer");
121 vkWaitForFences(device, 1, &m_inFlight[m_currentFrame], VK_TRUE, UINT64_MAX);
123 uint32_t imageIndex = 0;
124 VkResult acquire = vkAcquireNextImageKHR(device,
127 m_imageAvailable[m_currentFrame],
130 if (acquire == VK_ERROR_OUT_OF_DATE_KHR)
134 if (acquire != VK_SUCCESS && acquire != VK_SUBOPTIMAL_KHR)
136 Check(acquire,
"vkAcquireNextImageKHR");
139 vkResetFences(device, 1, &m_inFlight[m_currentFrame]);
140 vkResetCommandBuffer(m_cmdBuffers[m_currentFrame], 0);
141 RecordCommandBuffer(m_cmdBuffers[m_currentFrame], imageIndex, clearR, clearG, clearB);
143 VkSemaphore waitSems[] = { m_imageAvailable[m_currentFrame] };
144 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
145 VkSemaphore sigSems[] = { m_renderFinished[m_currentFrame] };
147 VkSubmitInfo submit{};
148 submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
149 submit.waitSemaphoreCount = 1;
150 submit.pWaitSemaphores = waitSems;
151 submit.pWaitDstStageMask = waitStages;
152 submit.commandBufferCount = 1;
153 submit.pCommandBuffers = &m_cmdBuffers[m_currentFrame];
154 submit.signalSemaphoreCount = 1;
155 submit.pSignalSemaphores = sigSems;
156 Check(vkQueueSubmit(m_ctx.
GetGraphicsQueue(), 1, &submit, m_inFlight[m_currentFrame]),
159 VkSwapchainKHR swap = m_swap.
Get();
160 VkPresentInfoKHR present{};
161 present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
162 present.waitSemaphoreCount = 1;
163 present.pWaitSemaphores = sigSems;
164 present.swapchainCount = 1;
165 present.pSwapchains = &swap;
166 present.pImageIndices = &imageIndex;
168 VkResult presentRes = vkQueuePresentKHR(m_ctx.
GetPresentQueue(), &present);
170 if (presentRes == VK_ERROR_OUT_OF_DATE_KHR || presentRes == VK_SUBOPTIMAL_KHR)
174 Check(presentRes,
"vkQueuePresentKHR");
Vulkan instance + physical/logical device + queue selection.
Per-frame Vulkan command-buffer recording + presentation.
VkSwapchain + per-image views, render pass, framebuffers.
Owns the Vulkan instance, surface (tied to a GLFW window), physical + logical device,...
VkQueue GetGraphicsQueue() const
QueueFamilies GetQueueFamilies() const
VkDevice GetDevice() const
VkQueue GetPresentQueue() const
Renderer(Context &ctx, Swapchain &swap)
bool DrawFrame(float clearR, float clearG, float clearB)
static constexpr uint32_t kFramesInFlight
VkRenderPass GetRenderPass() const
VkSwapchainKHR Get() const
VkExtent2D GetExtent() const
const std::vector< VkFramebuffer > & GetFramebuffers() const