Monad Engine da02fba2
> Undercity Codex_
Loading...
Searching...
No Matches
Renderer.cpp
Go to the documentation of this file.
2
3#include <stdexcept>
4#include <string>
5
8
9namespace mnd::vk
10{
11namespace
12{
13void Check(VkResult result, const char *what)
14{
15 if (result != VK_SUCCESS)
16 {
17 throw std::runtime_error(std::string("vk renderer: ") + what + " failed (VkResult=" +
18 std::to_string(static_cast<int>(result)) + ")");
19 }
20}
21} // namespace
22
23Renderer::Renderer(Context &ctx, Swapchain &swap) : m_ctx(ctx), m_swap(swap)
24{
25 CreateCommandPool();
26 AllocateCommandBuffers();
27 CreateSyncObjects();
28}
29
31{
32 auto device = m_ctx.GetDevice();
33 for (uint32_t i = 0; i < kFramesInFlight; ++i)
34 {
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);
38 }
39 if (m_cmdPool)
40 {
41 vkDestroyCommandPool(device, m_cmdPool, nullptr);
42 }
43}
44
46{
47 vkDeviceWaitIdle(m_ctx.GetDevice());
48}
49
50void Renderer::CreateCommandPool()
51{
52 VkCommandPoolCreateInfo info{};
53 info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
54 info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
55 info.queueFamilyIndex = m_ctx.GetQueueFamilies().graphics;
56 Check(vkCreateCommandPool(m_ctx.GetDevice(), &info, nullptr, &m_cmdPool),
57 "vkCreateCommandPool");
58}
59
60void Renderer::AllocateCommandBuffers()
61{
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;
66 info.commandBufferCount = kFramesInFlight;
67 Check(vkAllocateCommandBuffers(m_ctx.GetDevice(), &info, m_cmdBuffers.data()),
68 "vkAllocateCommandBuffers");
69}
70
71void Renderer::CreateSyncObjects()
72{
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; // start signalled so frame 0 doesn't deadlock
78
79 auto device = m_ctx.GetDevice();
80 for (uint32_t i = 0; i < kFramesInFlight; ++i)
81 {
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]),
87 "vkCreateFence");
88 }
89}
90
91void Renderer::RecordCommandBuffer(VkCommandBuffer cb, uint32_t imageIndex,
92 float r, float g, float b)
93{
94 VkCommandBufferBeginInfo begin{};
95 begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
96 Check(vkBeginCommandBuffer(cb, &begin), "vkBeginCommandBuffer");
97
98 VkClearValue clear{};
99 clear.color = { { r, g, b, 1.0f } };
100
101 VkRenderPassBeginInfo rp{};
102 rp.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
103 rp.renderPass = m_swap.GetRenderPass();
104 rp.framebuffer = m_swap.GetFramebuffers()[imageIndex];
105 rp.renderArea.offset = { 0, 0 };
106 rp.renderArea.extent = m_swap.GetExtent();
107 rp.clearValueCount = 1;
108 rp.pClearValues = &clear;
109
110 vkCmdBeginRenderPass(cb, &rp, VK_SUBPASS_CONTENTS_INLINE);
111 // No draw calls yet — this is intentionally a clear-only frame so the
112 // scaffold can be exercised before pipelines/shaders land.
113 vkCmdEndRenderPass(cb);
114
115 Check(vkEndCommandBuffer(cb), "vkEndCommandBuffer");
116}
117
118bool Renderer::DrawFrame(float clearR, float clearG, float clearB)
119{
120 auto device = m_ctx.GetDevice();
121 vkWaitForFences(device, 1, &m_inFlight[m_currentFrame], VK_TRUE, UINT64_MAX);
122
123 uint32_t imageIndex = 0;
124 VkResult acquire = vkAcquireNextImageKHR(device,
125 m_swap.Get(),
126 UINT64_MAX,
127 m_imageAvailable[m_currentFrame],
128 VK_NULL_HANDLE,
129 &imageIndex);
130 if (acquire == VK_ERROR_OUT_OF_DATE_KHR)
131 {
132 return false;
133 }
134 if (acquire != VK_SUCCESS && acquire != VK_SUBOPTIMAL_KHR)
135 {
136 Check(acquire, "vkAcquireNextImageKHR");
137 }
138
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);
142
143 VkSemaphore waitSems[] = { m_imageAvailable[m_currentFrame] };
144 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
145 VkSemaphore sigSems[] = { m_renderFinished[m_currentFrame] };
146
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]),
157 "vkQueueSubmit");
158
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;
167
168 VkResult presentRes = vkQueuePresentKHR(m_ctx.GetPresentQueue(), &present);
169 m_currentFrame = (m_currentFrame + 1) % kFramesInFlight;
170 if (presentRes == VK_ERROR_OUT_OF_DATE_KHR || presentRes == VK_SUBOPTIMAL_KHR)
171 {
172 return false;
173 }
174 Check(presentRes, "vkQueuePresentKHR");
175 return true;
176}
177
178} // namespace mnd::vk
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,...
Definition Context.h:41
VkQueue GetGraphicsQueue() const
Definition Context.h:59
QueueFamilies GetQueueFamilies() const
Definition Context.h:63
VkDevice GetDevice() const
Definition Context.h:57
VkQueue GetPresentQueue() const
Definition Context.h:61
void WaitIdle() const
Definition Renderer.cpp:45
Renderer(Context &ctx, Swapchain &swap)
Definition Renderer.cpp:23
bool DrawFrame(float clearR, float clearG, float clearB)
Definition Renderer.cpp:118
static constexpr uint32_t kFramesInFlight
Definition Renderer.h:26
VkRenderPass GetRenderPass() const
Definition Swapchain.h:36
VkSwapchainKHR Get() const
Definition Swapchain.h:35
VkExtent2D GetExtent() const
Definition Swapchain.h:37
const std::vector< VkFramebuffer > & GetFramebuffers() const
Definition Swapchain.h:39