diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index f883ed0c..52a0d377 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -84,6 +84,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -515,14 +516,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/18_vertex_input.cpp b/attachments/18_vertex_input.cpp index 4fee78bc..78801fb1 100644 --- a/attachments/18_vertex_input.cpp +++ b/attachments/18_vertex_input.cpp @@ -108,6 +108,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -263,8 +264,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -298,11 +300,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -532,14 +535,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index e1e12769..3d994cca 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -111,6 +111,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -267,8 +268,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -302,11 +304,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -564,14 +567,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 496de6aa..8bafd248 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -111,6 +111,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -267,8 +268,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -302,11 +304,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -583,14 +586,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index cb0124fb..cd488454 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -118,6 +118,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -275,8 +276,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -310,11 +312,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -608,14 +611,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 6d68a468..23646071 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -133,6 +133,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -292,8 +293,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -327,11 +329,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -663,14 +666,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 19210fce..a8884ce2 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -57,9 +57,9 @@ struct Vertex { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; const std::vector vertices = { @@ -136,6 +136,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -297,8 +298,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -332,11 +334,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -688,14 +691,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 36ceb3d7..25d2b6b9 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -60,9 +60,9 @@ struct Vertex { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; const std::vector vertices = { @@ -142,6 +142,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -304,8 +305,9 @@ class HelloTriangleApplication { { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } ); } ); - auto features = device.template getFeatures2(); - bool supportsRequiredFeatures = features.template get().dynamicRendering && + auto features = device.template getFeatures2(); + bool supportsRequiredFeatures = features.template get().shaderDrawParameters && + features.template get().dynamicRendering && features.template get().extendedDynamicState; return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures; @@ -339,11 +341,12 @@ class HelloTriangleApplication { throw std::runtime_error("Could not find a queue for graphics and present -> terminating"); } - // query for Vulkan 1.3 features - vk::StructureChain featureChain = { + // query for required features (Vulkan 1.1 and 1.3) + vk::StructureChain featureChain = { {}, // vk::PhysicalDeviceFeatures2 - {.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + { .shaderDrawParameters = true }, // vk::PhysicalDeviceVulkan11Features + { .synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features + { .extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT }; // create a Device @@ -792,14 +795,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 04c44ae9..29f6ec7b 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -60,9 +60,9 @@ struct Vertex { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; const std::vector vertices = { @@ -144,6 +144,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -827,14 +828,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR( presentInfoKHR ); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR( presentInfoKHR ); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index a1c25783..1173e787 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -62,9 +62,9 @@ struct Vertex { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; const std::vector vertices = { @@ -146,6 +146,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -904,14 +905,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index d6d143c1..c24b9aff 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -63,9 +63,9 @@ struct Vertex { }; struct UniformBufferObject { - alignas(16) glm::mat4 model; - alignas(16) glm::mat4 view; - alignas(16) glm::mat4 proj; + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; }; const std::vector vertices = { @@ -157,6 +157,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1032,14 +1033,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index faecc470..55bb91b3 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -159,6 +159,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1076,14 +1077,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index eb43a64b..b9fe9f27 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -160,6 +160,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1142,14 +1143,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 70c82bb0..a3a2efae 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -165,6 +165,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1214,14 +1215,23 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } semaphoreIndex = (semaphoreIndex + 1) % presentCompleteSemaphore.size(); currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index f0fb1d43..d4c09333 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -135,6 +135,7 @@ class ComputeShaderApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -862,12 +863,21 @@ class ComputeShaderApplication { .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfo); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + result = queue.presentKHR(presentInfo); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index 0b52d43a..ad8b0fa6 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -170,6 +170,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Compatibility Example", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1587,19 +1588,28 @@ class HelloTriangleApplication { queue.submit(submitInfo, *inFlightFences[currentFrame]); } - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphore[currentFrame], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex - }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphore[currentFrame], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex + }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 647ffa9a..ef061c12 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -161,6 +161,8 @@ class HelloTriangleApplication { void initWindow() { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Profiles Demo", nullptr, nullptr); glfwSetWindowUserPointer(window, this); glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); @@ -220,18 +222,11 @@ class HelloTriangleApplication { } void cleanupSwapChain() { - colorImageView = nullptr; - colorImage = nullptr; - colorImageMemory = nullptr; - - depthImageView = nullptr; - depthImage = nullptr; - depthImageMemory = nullptr; - - for (auto& framebuffer : swapChainFramebuffers) { - framebuffer = nullptr; - } + swapChainFramebuffers.clear(); + swapChainImageViews.clear(); + // Semaphores tied to swapchain image indices need to be rebuilt on resize + presentCompleteSemaphore.clear(); for (auto& imageView : swapChainImageViews) { imageView = nullptr; } @@ -268,6 +263,13 @@ class HelloTriangleApplication { createColorResources(); createDepthResources(); + + // Recreate per-swapchain-image present semaphores after resize + presentCompleteSemaphore.reserve(swapChainImages.size()); + vk::SemaphoreCreateInfo semaphoreInfo{}; + for (size_t i = 0; i < swapChainImages.size(); ++i) { + presentCompleteSemaphore.push_back(device.createSemaphore(semaphoreInfo)); + } } void createInstance() { @@ -1339,8 +1341,45 @@ class HelloTriangleApplication { void recordCommandBuffer(uint32_t imageIndex) { commandBuffers[currentFrame].begin({}); - // Transition the swapchain image to the correct layout for rendering - vk::ImageMemoryBarrier imageBarrier{ + // Transition the attachments to the correct layouts for dynamic rendering + // 1) Multisampled color attachment image -> ColorAttachmentOptimal + vk::ImageMemoryBarrier colorAttachmentBarrier{ + .srcAccessMask = vk::AccessFlagBits::eNone, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eColorAttachmentOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = *colorImage, + .subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + + // 2) Depth attachment image -> DepthStencilAttachmentOptimal + vk::ImageMemoryBarrier depthAttachmentBarrier{ + .srcAccessMask = vk::AccessFlagBits::eNone, + .dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = *depthImage, + .subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + + // 3) Resolve (swapchain) image -> ColorAttachmentOptimal + vk::ImageMemoryBarrier swapchainResolveBarrier{ .srcAccessMask = vk::AccessFlagBits::eNone, .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, .oldLayout = vk::ImageLayout::eUndefined, @@ -1359,11 +1398,11 @@ class HelloTriangleApplication { commandBuffers[currentFrame].pipelineBarrier( vk::PipelineStageFlagBits::eTopOfPipe, - vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, vk::DependencyFlagBits::eByRegion, std::array{}, std::array{}, - std::array{imageBarrier} + std::array{colorAttachmentBarrier, depthAttachmentBarrier, swapchainResolveBarrier} ); // Clear values for color and depth @@ -1549,28 +1588,29 @@ class HelloTriangleApplication { }; queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*presentCompleteSemaphore[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex - }; - - vk::Result result; try { - result = queue.presentKHR(presentInfoKHR); - } catch (vk::OutOfDateKHRError&) { - result = vk::Result::eErrorOutOfDateKHR; - } - - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + const vk::PresentInfoKHR presentInfoKHR{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*presentCompleteSemaphore[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex + }; + auto result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index a8786e98..83de8dc7 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -242,6 +242,7 @@ class HelloTriangleApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Cross-Platform", nullptr, nullptr); glfwSetWindowUserPointer(window, this); glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); @@ -1177,7 +1178,7 @@ class HelloTriangleApplication { // Create synchronization objects void createSyncObjects() { imageAvailableSemaphores.reserve(MAX_FRAMES_IN_FLIGHT); - renderFinishedSemaphores.reserve(MAX_FRAMES_IN_FLIGHT); + renderFinishedSemaphores.reserve(swapChainImages.size()); inFlightFences.reserve(MAX_FRAMES_IN_FLIGHT); vk::SemaphoreCreateInfo semaphoreInfo{}; @@ -1187,17 +1188,21 @@ class HelloTriangleApplication { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { imageAvailableSemaphores.push_back(device.createSemaphore(semaphoreInfo)); - renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo)); inFlightFences.push_back(device.createFence(fenceInfo)); } + + for (size_t i = 0; i < swapChainImages.size(); i++) { + renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo)); + } } // Clean up swap chain void cleanupSwapChain() { - for (auto& framebuffer : swapChainFramebuffers) { - framebuffer = nullptr; - } + swapChainFramebuffers.clear(); + swapChainImageViews.clear(); + // Semaphores tied to swapchain image indices need to be rebuilt on resize + renderFinishedSemaphores.clear(); for (auto& imageView : swapChainImageViews) { imageView = nullptr; } @@ -1282,30 +1287,34 @@ class HelloTriangleApplication { .commandBufferCount = 1, .pCommandBuffers = &*commandBuffers[currentFrame], .signalSemaphoreCount = 1, - .pSignalSemaphores = &*renderFinishedSemaphores[currentFrame] + .pSignalSemaphores = &*renderFinishedSemaphores[imageIndex] }; queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphores[currentFrame], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex - }; - - vk::Result result; try { - result = queue.presentKHR(presentInfoKHR); - } catch (vk::OutOfDateKHRError&) { - result = vk::Result::eErrorOutOfDateKHR; - } + const vk::PresentInfoKHR presentInfoKHR{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphores[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex + }; - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("Failed to present swap chain image"); + vk::Result result = queue.presentKHR(presentInfoKHR); + + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("Failed to present swap chain image"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -1313,16 +1322,34 @@ class HelloTriangleApplication { // Recreate swap chain void recreateSwapChain() { +#if !PLATFORM_ANDROID + // On desktop, wait until the framebuffer has a non-zero size (e.g., when window is minimized) + int width = 0, height = 0; + if (window) { + glfwGetFramebufferSize(window, &width, &height); + while (width == 0 || height == 0) { + glfwGetFramebufferSize(window, &width, &height); + glfwWaitEvents(); + } + } +#endif // Wait for device to finish operations device.waitIdle(); // Clean up old swap chain cleanupSwapChain(); - // Create new swap chain + // Create new swap chain and dependent resources createSwapChain(); createImageViews(); createFramebuffers(); + + // Recreate per-swapchain-image present semaphores for presenting + renderFinishedSemaphores.reserve(swapChainImages.size()); + vk::SemaphoreCreateInfo semaphoreInfo{}; + for (size_t i = 0; i < swapChainImages.size(); ++i) { + renderFinishedSemaphores.push_back(device.createSemaphore(semaphoreInfo)); + } } // Get required extensions diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 42f8ab7d..f1f07221 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -301,6 +301,7 @@ class VulkanApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1350,15 +1351,23 @@ class VulkanApplication { .signalSemaphoreCount = 1, .pSignalSemaphores = &*renderFinishedSemaphore[imageIndex] }; queue.submit(submitInfo, *inFlightFences[currentFrame]); - - const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ .waitSemaphoreCount = 1, .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, .pSwapchains = &*swapChain, .pImageIndices = &imageIndex }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 573ec003..4b1c0ccf 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -347,6 +347,7 @@ class VulkanApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); glfwSetWindowUserPointer(window, this); @@ -1478,19 +1479,28 @@ class VulkanApplication { }; queue.submit(submitInfo, *inFlightFences[currentFrame]); - const vk::PresentInfoKHR presentInfoKHR{ - .waitSemaphoreCount = 1, - .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], - .swapchainCount = 1, - .pSwapchains = &*swapChain, - .pImageIndices = &imageIndex - }; - result = queue.presentKHR(presentInfoKHR); - if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { - framebufferResized = false; - recreateSwapChain(); - } else if (result != vk::Result::eSuccess) { - throw std::runtime_error("failed to present swap chain image!"); + try { + const vk::PresentInfoKHR presentInfoKHR{ + .waitSemaphoreCount = 1, + .pWaitSemaphores = &*renderFinishedSemaphore[imageIndex], + .swapchainCount = 1, + .pSwapchains = &*swapChain, + .pImageIndices = &imageIndex + }; + result = queue.presentKHR(presentInfoKHR); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } + } catch (const vk::SystemError& e) { + if (e.code().value() == static_cast(vk::Result::eErrorOutOfDateKHR)) { + recreateSwapChain(); + return; + } else { + throw; + } } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index b6f9f719..b8dbaf76 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -186,7 +186,7 @@ class MultithreadedApplication { double lastFrameTime = 0.0; - // Removed resize-related variables and FSM state management as per simplification request + bool framebufferResized = false; double lastTime = 0.0f; @@ -237,7 +237,7 @@ class MultithreadedApplication { []( const auto & format ) { return format.format == vk::Format::eB8G8R8A8Srgb && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear; } ); return formatIt != availableFormats.end() ? *formatIt : availableFormats[0]; } - + static vk::PresentModeKHR chooseSwapPresentMode(const std::vector& availablePresentModes) { assert(std::ranges::any_of(availablePresentModes, [](auto presentMode){ return presentMode == vk::PresentModeKHR::eFifo; })); return std::ranges::any_of(availablePresentModes, @@ -279,14 +279,22 @@ class MultithreadedApplication { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Multithreading", nullptr, nullptr); glfwSetWindowUserPointer(window, this); + glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); lastTime = glfwGetTime(); } + static void framebufferResizeCallback(GLFWwindow* window, int, int) { + auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (app) { + app->framebufferResized = true; + } + } + void initVulkan() { createInstance(); createSurface(); @@ -436,6 +444,28 @@ class MultithreadedApplication { swapChain = nullptr; } + void recreateSwapChain() { + int width = 0, height = 0; + glfwGetFramebufferSize(window, &width, &height); + while (width == 0 || height == 0) { + glfwGetFramebufferSize(window, &width, &height); + glfwWaitEvents(); + } + device.waitIdle(); + + cleanupSwapChain(); + + createSwapChain(); + createImageViews(); + createComputeDescriptorSetLayout(); + createGraphicsPipeline(); + createComputePipeline(); + createShaderStorageBuffers(); + createUniformBuffers(); + createDescriptorPool(); + createComputeDescriptorSets(); + } + void stopThreads() { shouldExit.store(true, std::memory_order_release); @@ -1074,10 +1104,22 @@ class MultithreadedApplication { // Wait for the previous frame to finish while (vk::Result::eTimeout == device.waitForFences(*inFlightFences[currentFrame], vk::True, UINT64_MAX)) ; - device.resetFences(*inFlightFences[currentFrame]); + + // If the framebuffer was resized, rebuild the swap chain before acquiring a new image + if (framebufferResized) { + recreateSwapChain(); + framebufferResized = false; + return; + } // Acquire the next image auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *imageAvailableSemaphores[currentFrame], nullptr); + if (result == vk::Result::eErrorOutOfDateKHR) { + recreateSwapChain(); + return; + } else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { + throw std::runtime_error("failed to acquire swap chain image!"); + } // Update timeline values for synchronization uint64_t computeWaitValue = timelineValue; @@ -1167,6 +1209,7 @@ class MultithreadedApplication { // Submit graphics work { std::lock_guard lock(queueSubmitMutex); + device.resetFences(*inFlightFences[currentFrame]); queue.submit(graphicsSubmitInfo, *inFlightFences[currentFrame]); } @@ -1193,6 +1236,13 @@ class MultithreadedApplication { }; result = queue.presentKHR(presentInfo); + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || framebufferResized) { + framebufferResized = false; + recreateSwapChain(); + return; + } else if (result != vk::Result::eSuccess) { + throw std::runtime_error("failed to present swap chain image!"); + } // Move to the next frame currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;