58 if (m_imagesInFlight[*imageIndex] != VK_NULL_HANDLE) {
59 vkWaitForFences(m_device.device(), 1, &m_imagesInFlight[*imageIndex], VK_TRUE, UINT64_MAX);
61 m_imagesInFlight[*imageIndex] = m_inFlightFences[m_currentFrame];
63 VkSubmitInfo submitInfo = {};
64 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
66 const std::array<VkSemaphore, 1> waitSemaphores = {m_imageAvailableSemaphores[m_currentFrame]};
67 constexpr std::array<VkPipelineStageFlags, 1> waitStages = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
68 submitInfo.waitSemaphoreCount = 1;
69 submitInfo.pWaitSemaphores = waitSemaphores.data();
70 submitInfo.pWaitDstStageMask = waitStages.data();
72 submitInfo.commandBufferCount = 1;
73 submitInfo.pCommandBuffers = buffers;
75 const std::array<VkSemaphore, 1> signalSemaphores = {m_renderFinishedSemaphores[m_currentFrame]};
76 submitInfo.signalSemaphoreCount = 1;
77 submitInfo.pSignalSemaphores = signalSemaphores.data();
79 vkResetFences(m_device.device(), 1, &m_inFlightFences[m_currentFrame]);
80 if (vkQueueSubmit(m_device.graphicsQueue(), 1, &submitInfo, m_inFlightFences[m_currentFrame]) != VK_SUCCESS) {
81 throw std::runtime_error(
"failed to submit draw command buffer!");
84 VkPresentInfoKHR presentInfo = {};
85 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
87 presentInfo.waitSemaphoreCount = 1;
88 presentInfo.pWaitSemaphores = signalSemaphores.data();
90 const std::array<VkSwapchainKHR, 1> swapChains = {m_swapChain};
91 presentInfo.swapchainCount = 1;
92 presentInfo.pSwapchains = swapChains.data();
94 presentInfo.pImageIndices = imageIndex;
96 const VkResult result = vkQueuePresentKHR(m_device.presentQueue(), &presentInfo);
105 const auto [capabilities, formats, presentModes] = m_device.getSwapChainSupport();
107 const auto [format, colorSpace] = chooseSwapSurfaceFormat(formats);
108 const VkPresentModeKHR presentMode = chooseSwapPresentMode(presentModes);
109 const VkExtent2D extent = chooseSwapExtent(capabilities);
111 uint32_t imageCount = capabilities.minImageCount + 1;
112 if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
113 imageCount = capabilities.maxImageCount;
116 VkSwapchainCreateInfoKHR createInfo = {};
117 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
118 createInfo.surface = m_device.surface();
120 createInfo.minImageCount = imageCount;
121 createInfo.imageFormat = format;
122 createInfo.imageColorSpace = colorSpace;
123 createInfo.imageExtent = extent;
124 createInfo.imageArrayLayers = 1;
125 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
127 const auto [graphicsFamily, presentFamily, graphicsFamilyHasValue, presentFamilyHasValue] = m_device.findPhysicalQueueFamilies();
128 const std::array<uint32_t, 2> queueFamilyIndices = {graphicsFamily, presentFamily};
130 if (graphicsFamily != presentFamily) {
131 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
132 createInfo.queueFamilyIndexCount = 2;
133 createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
135 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
136 createInfo.queueFamilyIndexCount = 0;
137 createInfo.pQueueFamilyIndices =
nullptr;
140 createInfo.preTransform = capabilities.currentTransform;
141 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
143 createInfo.presentMode = presentMode;
144 createInfo.clipped = VK_TRUE;
146 createInfo.oldSwapchain = m_oldSwapChain ==
nullptr ? VK_NULL_HANDLE : m_oldSwapChain->m_swapChain;
148 if (vkCreateSwapchainKHR(m_device.device(), &createInfo,
nullptr, &m_swapChain) != VK_SUCCESS) {
149 throw std::runtime_error(
"failed to create swap chain!");
152 vkGetSwapchainImagesKHR(m_device.device(), m_swapChain, &imageCount,
nullptr);
153 m_swapChainImages.resize(imageCount);
154 vkGetSwapchainImagesKHR(m_device.device(), m_swapChain, &imageCount, m_swapChainImages.data());
156 m_swapChainImageFormat = format;
157 m_swapChainExtent = extent;
162 m_swapChainImageViews.resize(m_swapChainImages.size());
163 for (
size_t i = 0; i < m_swapChainImages.size(); i++) {
164 VkImageViewCreateInfo viewInfo{};
165 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
166 viewInfo.image = m_swapChainImages[i];
167 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
168 viewInfo.format = m_swapChainImageFormat;
169 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
170 viewInfo.subresourceRange.baseMipLevel = 0;
171 viewInfo.subresourceRange.levelCount = 1;
172 viewInfo.subresourceRange.baseArrayLayer = 0;
173 viewInfo.subresourceRange.layerCount = 1;
175 if (vkCreateImageView(m_device.device(), &viewInfo,
nullptr, &m_swapChainImageViews[i]) != VK_SUCCESS) {
176 throw std::runtime_error(
"failed to create texture image view!");
183 VkAttachmentDescription depthAttachment{};
184 depthAttachment.format = findDepthFormat();
185 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
186 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
187 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
188 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
189 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
190 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
191 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
193 VkAttachmentReference depthAttachmentRef{};
194 depthAttachmentRef.attachment = 1;
195 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
197 VkAttachmentDescription colorAttachment = {};
198 colorAttachment.format = getSwapChainImageFormat();
199 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
200 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
201 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
202 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
203 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
204 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
205 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
207 VkAttachmentReference colorAttachmentRef = {};
208 colorAttachmentRef.attachment = 0;
209 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
211 VkSubpassDescription subpass = {};
212 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
213 subpass.colorAttachmentCount = 1;
214 subpass.pColorAttachments = &colorAttachmentRef;
215 subpass.pDepthStencilAttachment = &depthAttachmentRef;
217 VkSubpassDependency dependency = {};
218 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
219 dependency.srcAccessMask = 0;
220 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
221 dependency.dstSubpass = 0;
222 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
223 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
225 const std::array<VkAttachmentDescription, 2> attachments = {colorAttachment, depthAttachment};
226 VkRenderPassCreateInfo renderPassInfo = {};
227 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
228 renderPassInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
229 renderPassInfo.pAttachments = attachments.data();
230 renderPassInfo.subpassCount = 1;
231 renderPassInfo.pSubpasses = &subpass;
232 renderPassInfo.dependencyCount = 1;
233 renderPassInfo.pDependencies = &dependency;
235 if (vkCreateRenderPass(m_device.device(), &renderPassInfo,
nullptr, &m_renderPass) != VK_SUCCESS) {
236 throw std::runtime_error(
"failed to create render pass!");
242 m_swapChainFrameBuffers.resize(imageCount());
243 for (
size_t i = 0; i < imageCount(); i++) {
244 std::array<VkImageView, 2> attachments = {m_swapChainImageViews[i], m_depthImageViews[i]};
246 const auto [width, height] = getSwapChainExtent();
247 VkFramebufferCreateInfo framebufferInfo = {};
248 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
249 framebufferInfo.renderPass = m_renderPass;
250 framebufferInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
251 framebufferInfo.pAttachments = attachments.data();
252 framebufferInfo.width = width;
253 framebufferInfo.height = height;
254 framebufferInfo.layers = 1;
256 if (vkCreateFramebuffer(m_device.device(), &framebufferInfo,
nullptr, &m_swapChainFrameBuffers[i]) != VK_SUCCESS) {
257 throw std::runtime_error(
"failed to create framebuffer!");
264 const VkFormat depthFormat = findDepthFormat();
265 const auto [width, height] = getSwapChainExtent();
267 m_swapChainDepthFormat = depthFormat;
268 m_depthImages.resize(imageCount());
269 m_depthImageMemory.resize(imageCount());
270 m_depthImageViews.resize(imageCount());
272 for (
size_t i = 0; i < m_depthImages.size(); i++) {
273 VkImageCreateInfo imageInfo{};
274 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
275 imageInfo.imageType = VK_IMAGE_TYPE_2D;
276 imageInfo.extent.width = width;
277 imageInfo.extent.height = height;
278 imageInfo.extent.depth = 1;
279 imageInfo.mipLevels = 1;
280 imageInfo.arrayLayers = 1;
281 imageInfo.format = depthFormat;
282 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
283 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
284 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
285 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
286 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
289 m_device.createImageWithInfo(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_depthImages[i], m_depthImageMemory[i]);
291 VkImageViewCreateInfo viewInfo{};
292 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
293 viewInfo.image = m_depthImages[i];
294 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
295 viewInfo.format = depthFormat;
296 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
297 viewInfo.subresourceRange.baseMipLevel = 0;
298 viewInfo.subresourceRange.levelCount = 1;
299 viewInfo.subresourceRange.baseArrayLayer = 0;
300 viewInfo.subresourceRange.layerCount = 1;
302 if (vkCreateImageView(m_device.device(), &viewInfo,
nullptr, &m_depthImageViews[i]) != VK_SUCCESS) {
303 throw std::runtime_error(
"failed to create texture image view!");
313 m_imagesInFlight.resize(imageCount(), VK_NULL_HANDLE);
315 VkSemaphoreCreateInfo semaphoreInfo = {};
316 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
318 VkFenceCreateInfo fenceInfo = {};
319 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
320 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
323 if (vkCreateSemaphore(m_device.device(), &semaphoreInfo,
nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS ||
324 vkCreateSemaphore(m_device.device(), &semaphoreInfo,
nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS ||
325 vkCreateFence(m_device.device(), &fenceInfo,
nullptr, &m_inFlightFences[i]) != VK_SUCCESS) {
326 throw std::runtime_error(
"failed to create synchronization objects for a frame!");
364 if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
365 return capabilities.currentExtent;
367 VkExtent2D actualExtent = m_windowExtent;
368 actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
369 actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));