58 if (imagesInFlight[*imageIndex] != VK_NULL_HANDLE) {
59 vkWaitForFences(device.device(), 1, &imagesInFlight[*imageIndex], VK_TRUE, UINT64_MAX);
61 imagesInFlight[*imageIndex] = inFlightFences[currentFrame];
63 VkSubmitInfo submitInfo = {};
64 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
66 const VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
67 constexpr VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
68 submitInfo.waitSemaphoreCount = 1;
69 submitInfo.pWaitSemaphores = waitSemaphores;
70 submitInfo.pWaitDstStageMask = waitStages;
72 submitInfo.commandBufferCount = 1;
73 submitInfo.pCommandBuffers = buffers;
75 const VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
76 submitInfo.signalSemaphoreCount = 1;
77 submitInfo.pSignalSemaphores = signalSemaphores;
79 vkResetFences(device.device(), 1, &inFlightFences[currentFrame]);
80 if (vkQueueSubmit(device.graphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
81 throw std::runtime_error(
"failed to submit draw command m_buffer!");
84 VkPresentInfoKHR presentInfo = {};
85 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
87 presentInfo.waitSemaphoreCount = 1;
88 presentInfo.pWaitSemaphores = signalSemaphores;
90 const VkSwapchainKHR swapChains[] = {swapChain};
91 presentInfo.swapchainCount = 1;
92 presentInfo.pSwapchains = swapChains;
94 presentInfo.pImageIndices = imageIndex;
96 const VkResult result = vkQueuePresentKHR(device.presentQueue(), &presentInfo);
98 currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
107 const VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.
formats);
108 const VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.
presentModes);
109 const VkExtent2D extent = chooseSwapExtent(swapChainSupport.
capabilities);
111 uint32_t imageCount = swapChainSupport.
capabilities.minImageCount + 1;
113 imageCount = swapChainSupport.
capabilities.maxImageCount;
116 VkSwapchainCreateInfoKHR createInfo = {};
117 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
118 createInfo.surface = device.surface();
120 createInfo.minImageCount = imageCount;
121 createInfo.imageFormat = surfaceFormat.format;
122 createInfo.imageColorSpace = surfaceFormat.colorSpace;
123 createInfo.imageExtent = extent;
124 createInfo.imageArrayLayers = 1;
125 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
131 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
132 createInfo.queueFamilyIndexCount = 2;
133 createInfo.pQueueFamilyIndices = queueFamilyIndices;
135 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
136 createInfo.queueFamilyIndexCount = 0;
137 createInfo.pQueueFamilyIndices =
nullptr;
140 createInfo.preTransform = swapChainSupport.
capabilities.currentTransform;
141 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
143 createInfo.presentMode = presentMode;
144 createInfo.clipped = VK_TRUE;
146 createInfo.oldSwapchain = oldSwapChain ==
nullptr ? VK_NULL_HANDLE : oldSwapChain->swapChain;
148 if (vkCreateSwapchainKHR(device.device(), &createInfo,
nullptr, &swapChain) != VK_SUCCESS) {
149 throw std::runtime_error(
"failed to create swap chain!");
156 vkGetSwapchainImagesKHR(device.device(), swapChain, &imageCount,
nullptr);
157 swapChainImages.resize(imageCount);
158 vkGetSwapchainImagesKHR(device.device(), swapChain, &imageCount, swapChainImages.data());
160 swapChainImageFormat = surfaceFormat.format;
161 m_swapChainExtent = extent;
166 swapChainImageViews.resize(swapChainImages.size());
167 for (
size_t i = 0; i < swapChainImages.size(); i++) {
168 VkImageViewCreateInfo viewInfo{};
169 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
170 viewInfo.image = swapChainImages[i];
171 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
172 viewInfo.format = swapChainImageFormat;
173 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
174 viewInfo.subresourceRange.baseMipLevel = 0;
175 viewInfo.subresourceRange.levelCount = 1;
176 viewInfo.subresourceRange.baseArrayLayer = 0;
177 viewInfo.subresourceRange.layerCount = 1;
179 if (vkCreateImageView(device.device(), &viewInfo,
nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
180 throw std::runtime_error(
"failed to create texture image view!");
187 VkAttachmentDescription depthAttachment{};
188 depthAttachment.format = findDepthFormat();
189 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
190 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
191 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
192 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
193 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
194 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
195 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
197 VkAttachmentReference depthAttachmentRef{};
198 depthAttachmentRef.attachment = 1;
199 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
201 VkAttachmentDescription colorAttachment = {};
202 colorAttachment.format = getSwapChainImageFormat();
203 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
204 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
205 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
206 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
207 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
208 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
209 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
211 VkAttachmentReference colorAttachmentRef = {};
212 colorAttachmentRef.attachment = 0;
213 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
215 VkSubpassDescription subpass = {};
216 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
217 subpass.colorAttachmentCount = 1;
218 subpass.pColorAttachments = &colorAttachmentRef;
219 subpass.pDepthStencilAttachment = &depthAttachmentRef;
221 VkSubpassDependency dependency = {};
222 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
223 dependency.srcAccessMask = 0;
224 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
225 dependency.dstSubpass = 0;
226 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
227 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
229 const std::array<VkAttachmentDescription, 2> attachments = {colorAttachment, depthAttachment};
230 VkRenderPassCreateInfo renderPassInfo = {};
231 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
232 renderPassInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
233 renderPassInfo.pAttachments = attachments.data();
234 renderPassInfo.subpassCount = 1;
235 renderPassInfo.pSubpasses = &subpass;
236 renderPassInfo.dependencyCount = 1;
237 renderPassInfo.pDependencies = &dependency;
239 if (vkCreateRenderPass(device.device(), &renderPassInfo,
nullptr, &renderPass) != VK_SUCCESS) {
240 throw std::runtime_error(
"failed to create render pass!");
246 swapChainFramebuffers.resize(imageCount());
247 for (
size_t i = 0; i < imageCount(); i++) {
248 std::array<VkImageView, 2> attachments = {swapChainImageViews[i], depthImageViews[i]};
250 const VkExtent2D swapChainExtent = getSwapChainExtent();
251 VkFramebufferCreateInfo framebufferInfo = {};
252 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
253 framebufferInfo.renderPass = renderPass;
254 framebufferInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
255 framebufferInfo.pAttachments = attachments.data();
256 framebufferInfo.width = swapChainExtent.width;
257 framebufferInfo.height = swapChainExtent.height;
258 framebufferInfo.layers = 1;
260 if (vkCreateFramebuffer(device.device(), &framebufferInfo,
nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
261 throw std::runtime_error(
"failed to create framebuffer!");
268 const VkFormat depthFormat = findDepthFormat();
269 const VkExtent2D swapChainExtent = getSwapChainExtent();
271 swapChainDepthFormat = depthFormat;
272 depthImages.resize(imageCount());
273 depthImageMemorys.resize(imageCount());
274 depthImageViews.resize(imageCount());
276 for (
size_t i = 0; i < depthImages.size(); i++) {
277 VkImageCreateInfo imageInfo{};
278 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
279 imageInfo.imageType = VK_IMAGE_TYPE_2D;
280 imageInfo.extent.width = swapChainExtent.width;
281 imageInfo.extent.height = swapChainExtent.height;
282 imageInfo.extent.depth = 1;
283 imageInfo.mipLevels = 1;
284 imageInfo.arrayLayers = 1;
285 imageInfo.format = depthFormat;
286 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
287 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
288 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
289 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
290 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
293 device.createImageWithInfo(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImages[i], depthImageMemorys[i]);
295 VkImageViewCreateInfo viewInfo{};
296 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
297 viewInfo.image = depthImages[i];
298 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
299 viewInfo.format = depthFormat;
300 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
301 viewInfo.subresourceRange.baseMipLevel = 0;
302 viewInfo.subresourceRange.levelCount = 1;
303 viewInfo.subresourceRange.baseArrayLayer = 0;
304 viewInfo.subresourceRange.layerCount = 1;
306 if (vkCreateImageView(device.device(), &viewInfo,
nullptr, &depthImageViews[i]) != VK_SUCCESS) {
307 throw std::runtime_error(
"failed to create texture image view!");
314 imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
315 renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
316 inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
317 imagesInFlight.resize(imageCount(), VK_NULL_HANDLE);
319 VkSemaphoreCreateInfo semaphoreInfo = {};
320 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
322 VkFenceCreateInfo fenceInfo = {};
323 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
324 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
326 for (
size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
327 if (vkCreateSemaphore(device.device(), &semaphoreInfo,
nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
328 vkCreateSemaphore(device.device(), &semaphoreInfo,
nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
329 vkCreateFence(device.device(), &fenceInfo,
nullptr, &inFlightFences[i]) != VK_SUCCESS) {
330 throw std::runtime_error(
"failed to create synchronization objects for a frame!");
368 if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
369 return capabilities.currentExtent;
371 VkExtent2D actualExtent = windowExtent;
372 actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
373 actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));