diff --git a/.vscode/settings.json b/.vscode/settings.json index 8629118..961290f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -48,6 +48,30 @@ "typeinfo": "cpp", "fstream": "cpp", "set": "cpp", - "unordered_set": "cpp" + "unordered_set": "cpp", + "csignal": "cpp", + "ctime": "cpp", + "any": "cpp", + "strstream": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "list": "cpp", + "map": "cpp", + "optional": "cpp", + "ratio": "cpp", + "future": "cpp", + "iomanip": "cpp", + "mutex": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "typeindex": "cpp", + "valarray": "cpp", + "variant": "cpp" } } \ No newline at end of file diff --git a/VulkanTest b/VulkanTest index ac9015b..e5eaaec 100755 Binary files a/VulkanTest and b/VulkanTest differ diff --git a/first_app.cpp b/first_app.cpp index 11eb003..8447b5f 100644 --- a/first_app.cpp +++ b/first_app.cpp @@ -58,8 +58,11 @@ namespace hk void FirstApp::createPipeline() { - auto pipelineConfig = - Pipeline::defaultPipelineConfigInfo(swapChain->width(), swapChain->height()); + assert(swapChain != nullptr && "Cannot create pipeline before swap chain"); + assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout"); + + PipelineConfigInfo pipelineConfig{}; + Pipeline::defaultPipelineConfigInfo(pipelineConfig); pipelineConfig.renderPass = swapChain->getRenderPass(); pipelineConfig.pipelineLayout = pipelineLayout; @@ -80,7 +83,22 @@ namespace hk } vkDeviceWaitIdle(device.device()); - swapChain = std::make_unique(device, extent); + + if (swapChain == nullptr) + { + swapChain = std::make_unique(device, extent); + } + else + { + swapChain = std::make_unique(device, extent, std::move(swapChain)); + if (swapChain->imageCount() != commandBuffers.size()) + { + freeCommandBuffers(); + createCommandBuffers(); + } + } + + // if render pass compatible do nothing else createPipeline(); } @@ -101,6 +119,16 @@ namespace hk } } + void FirstApp::freeCommandBuffers() + { + vkFreeCommandBuffers( + device.device(), + device.getCommandPool(), + static_cast(commandBuffers.size()), + commandBuffers.data()); + commandBuffers.clear(); + } + void FirstApp::recordCommandBuffer(int imageIndex) { VkCommandBufferBeginInfo beginInfo{}; @@ -126,6 +154,17 @@ namespace hk vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapChain->getSwapChainExtent().width); + viewport.height = static_cast(swapChain->getSwapChainExtent().height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + VkRect2D scissor{{0, 0}, swapChain->getSwapChainExtent()}; + vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); + vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); + pipeline->bind(commandBuffers[imageIndex]); model->bind(commandBuffers[imageIndex]); model->draw(commandBuffers[imageIndex]); @@ -161,7 +200,7 @@ namespace hk recreateSwapChain(); return; } - + if (result != VK_SUCCESS) { throw std::runtime_error("failed to present swap chain image!"); diff --git a/first_app.hpp b/first_app.hpp index 4d19d66..e84fb4a 100644 --- a/first_app.hpp +++ b/first_app.hpp @@ -31,6 +31,7 @@ namespace hk void createPipelineLayout(); void createPipeline(); void createCommandBuffers(); + void freeCommandBuffers(); void drawFrame(); void recreateSwapChain(); void recordCommandBuffer(int imageIndex); diff --git a/hk_pipeline.cpp b/hk_pipeline.cpp index 6b17f91..4c211b9 100644 --- a/hk_pipeline.cpp +++ b/hk_pipeline.cpp @@ -31,22 +31,17 @@ namespace hk vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicPipeline); } - PipelineConfigInfo Pipeline::defaultPipelineConfigInfo(uint32_t width, uint32_t height) + void Pipeline::defaultPipelineConfigInfo(PipelineConfigInfo& configInfo) { - PipelineConfigInfo configInfo{}; configInfo.inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; configInfo.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; configInfo.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; - configInfo.viewport.x = 0.0f; - configInfo.viewport.y = 0.0f; - configInfo.viewport.width = static_cast(width); - configInfo.viewport.height = static_cast(height); - configInfo.viewport.minDepth = 0.0f; - configInfo.viewport.maxDepth = 1.0f; - - configInfo.scissor.offset = {0, 0}; - configInfo.scissor.extent = {width, height}; + configInfo.viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + configInfo.viewportInfo.viewportCount = 1; + configInfo.viewportInfo.pViewports = nullptr; + configInfo.viewportInfo.scissorCount = 1; + configInfo.viewportInfo.pScissors = nullptr; configInfo.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; configInfo.rasterizationInfo.depthClampEnable = VK_FALSE; @@ -100,7 +95,11 @@ namespace hk configInfo.depthStencilInfo.front = {}; // Optional configInfo.depthStencilInfo.back = {}; // Optional - return configInfo; + configInfo.dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + configInfo.dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + configInfo.dynamicStateInfo.pDynamicStates = configInfo.dynamicStateEnables.data(); + configInfo.dynamicStateInfo.dynamicStateCount = static_cast(configInfo.dynamicStateEnables.size()); + configInfo.dynamicStateInfo.flags = 0; } std::vector Pipeline::readFile(const std::string &filePath) @@ -165,25 +164,18 @@ namespace hk vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.data(); - VkPipelineViewportStateCreateInfo viewportInfo{}; - viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportInfo.viewportCount = 1; - viewportInfo.pViewports = &configInfo.viewport; - viewportInfo.scissorCount = 1; - viewportInfo.pScissors = &configInfo.scissor; - VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = 2; pipelineInfo.pStages = shaderStages; pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pInputAssemblyState = &configInfo.inputAssemblyInfo; - pipelineInfo.pViewportState = &viewportInfo; + pipelineInfo.pViewportState = &configInfo.viewportInfo; pipelineInfo.pRasterizationState = &configInfo.rasterizationInfo; pipelineInfo.pMultisampleState = &configInfo.multisampleInfo; pipelineInfo.pColorBlendState = &configInfo.colorBlendInfo; pipelineInfo.pDepthStencilState = &configInfo.depthStencilInfo; - pipelineInfo.pDynamicState = nullptr; + pipelineInfo.pDynamicState = &configInfo.dynamicStateInfo; pipelineInfo.layout = configInfo.pipelineLayout; pipelineInfo.renderPass = configInfo.renderPass; diff --git a/hk_pipeline.hpp b/hk_pipeline.hpp index b74196e..06a9f6a 100644 --- a/hk_pipeline.hpp +++ b/hk_pipeline.hpp @@ -10,14 +10,18 @@ namespace hk { struct PipelineConfigInfo { - VkViewport viewport; - VkRect2D scissor; + PipelineConfigInfo(const PipelineConfigInfo&) = delete; + PipelineConfigInfo &operator=(const PipelineConfigInfo&) = delete; + + VkPipelineViewportStateCreateInfo viewportInfo; VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo; VkPipelineRasterizationStateCreateInfo rasterizationInfo; VkPipelineMultisampleStateCreateInfo multisampleInfo; VkPipelineColorBlendAttachmentState colorBlendAttachment; VkPipelineColorBlendStateCreateInfo colorBlendInfo; VkPipelineDepthStencilStateCreateInfo depthStencilInfo; + std::vector dynamicStateEnables; + VkPipelineDynamicStateCreateInfo dynamicStateInfo; VkPipelineLayout pipelineLayout = nullptr; VkRenderPass renderPass = nullptr; uint32_t subpass = 0; @@ -38,7 +42,7 @@ namespace hk void bind(VkCommandBuffer commandBuffer); - static PipelineConfigInfo defaultPipelineConfigInfo(uint32_t width, uint32_t height); + static void defaultPipelineConfigInfo(PipelineConfigInfo& configInfo); private: static std::vector readFile(const std::string &filePath); diff --git a/hk_swap_chain.cpp b/hk_swap_chain.cpp index 7415397..2382a46 100644 --- a/hk_swap_chain.cpp +++ b/hk_swap_chain.cpp @@ -14,6 +14,19 @@ namespace hk SwapChain::SwapChain(Device &deviceRef, VkExtent2D extent) : device{deviceRef}, windowExtent{extent} + { + init(); + } + SwapChain::SwapChain(Device &deviceRef, VkExtent2D extent, std::shared_ptr previous) + : device{deviceRef}, windowExtent{extent}, oldSwapChain{previous} + { + init(); + + // clean up old swap chain + oldSwapChain = nullptr; + } + + void SwapChain::init() { createSwapChain(); createImageViews(); @@ -179,7 +192,7 @@ namespace hk createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = VK_NULL_HANDLE; + createInfo.oldSwapchain = oldSwapChain == nullptr ? VK_NULL_HANDLE : oldSwapChain->swapChain; if (vkCreateSwapchainKHR(device.device(), &createInfo, nullptr, &swapChain) != VK_SUCCESS) { diff --git a/hk_swap_chain.hpp b/hk_swap_chain.hpp index 6f7a9e7..9af59b9 100644 --- a/hk_swap_chain.hpp +++ b/hk_swap_chain.hpp @@ -6,6 +6,7 @@ #include // std lib headers +#include #include #include @@ -18,6 +19,7 @@ namespace hk static constexpr int MAX_FRAMES_IN_FLIGHT = 2; SwapChain(Device &deviceRef, VkExtent2D windowExtent); + SwapChain(Device &deviceRef, VkExtent2D windowExtent, std::shared_ptr previous); ~SwapChain(); SwapChain(const SwapChain &) = delete; @@ -42,6 +44,7 @@ namespace hk VkResult submitCommandBuffers(const VkCommandBuffer *buffers, uint32_t *imageIndex); private: + void init(); void createSwapChain(); void createImageViews(); void createDepthResources(); @@ -72,6 +75,7 @@ namespace hk VkExtent2D windowExtent; VkSwapchainKHR swapChain; + std::shared_ptr oldSwapChain; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores;