Swap Chain Recreation & Dynamic Viewports

This commit is contained in:
hoenking 2024-02-21 21:01:49 +08:00
parent eb484e22f8
commit 976ff14298
8 changed files with 107 additions and 30 deletions

26
.vscode/settings.json vendored
View File

@ -48,6 +48,30 @@
"typeinfo": "cpp", "typeinfo": "cpp",
"fstream": "cpp", "fstream": "cpp",
"set": "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"
} }
} }

Binary file not shown.

View File

@ -58,8 +58,11 @@ namespace hk
void FirstApp::createPipeline() void FirstApp::createPipeline()
{ {
auto pipelineConfig = assert(swapChain != nullptr && "Cannot create pipeline before swap chain");
Pipeline::defaultPipelineConfigInfo(swapChain->width(), swapChain->height()); assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout");
PipelineConfigInfo pipelineConfig{};
Pipeline::defaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.renderPass = swapChain->getRenderPass(); pipelineConfig.renderPass = swapChain->getRenderPass();
pipelineConfig.pipelineLayout = pipelineLayout; pipelineConfig.pipelineLayout = pipelineLayout;
@ -80,7 +83,22 @@ namespace hk
} }
vkDeviceWaitIdle(device.device()); vkDeviceWaitIdle(device.device());
swapChain = std::make_unique<SwapChain>(device, extent);
if (swapChain == nullptr)
{
swapChain = std::make_unique<SwapChain>(device, extent);
}
else
{
swapChain = std::make_unique<SwapChain>(device, extent, std::move(swapChain));
if (swapChain->imageCount() != commandBuffers.size())
{
freeCommandBuffers();
createCommandBuffers();
}
}
// if render pass compatible do nothing else
createPipeline(); createPipeline();
} }
@ -101,6 +119,16 @@ namespace hk
} }
} }
void FirstApp::freeCommandBuffers()
{
vkFreeCommandBuffers(
device.device(),
device.getCommandPool(),
static_cast<float>(commandBuffers.size()),
commandBuffers.data());
commandBuffers.clear();
}
void FirstApp::recordCommandBuffer(int imageIndex) void FirstApp::recordCommandBuffer(int imageIndex)
{ {
VkCommandBufferBeginInfo beginInfo{}; VkCommandBufferBeginInfo beginInfo{};
@ -126,6 +154,17 @@ namespace hk
vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(swapChain->getSwapChainExtent().width);
viewport.height = static_cast<float>(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]); pipeline->bind(commandBuffers[imageIndex]);
model->bind(commandBuffers[imageIndex]); model->bind(commandBuffers[imageIndex]);
model->draw(commandBuffers[imageIndex]); model->draw(commandBuffers[imageIndex]);
@ -161,7 +200,7 @@ namespace hk
recreateSwapChain(); recreateSwapChain();
return; return;
} }
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
throw std::runtime_error("failed to present swap chain image!"); throw std::runtime_error("failed to present swap chain image!");

View File

@ -31,6 +31,7 @@ namespace hk
void createPipelineLayout(); void createPipelineLayout();
void createPipeline(); void createPipeline();
void createCommandBuffers(); void createCommandBuffers();
void freeCommandBuffers();
void drawFrame(); void drawFrame();
void recreateSwapChain(); void recreateSwapChain();
void recordCommandBuffer(int imageIndex); void recordCommandBuffer(int imageIndex);

View File

@ -31,22 +31,17 @@ namespace hk
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicPipeline); 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.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
configInfo.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; configInfo.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
configInfo.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; configInfo.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE;
configInfo.viewport.x = 0.0f; configInfo.viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
configInfo.viewport.y = 0.0f; configInfo.viewportInfo.viewportCount = 1;
configInfo.viewport.width = static_cast<float>(width); configInfo.viewportInfo.pViewports = nullptr;
configInfo.viewport.height = static_cast<float>(height); configInfo.viewportInfo.scissorCount = 1;
configInfo.viewport.minDepth = 0.0f; configInfo.viewportInfo.pScissors = nullptr;
configInfo.viewport.maxDepth = 1.0f;
configInfo.scissor.offset = {0, 0};
configInfo.scissor.extent = {width, height};
configInfo.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; configInfo.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
configInfo.rasterizationInfo.depthClampEnable = VK_FALSE; configInfo.rasterizationInfo.depthClampEnable = VK_FALSE;
@ -100,7 +95,11 @@ namespace hk
configInfo.depthStencilInfo.front = {}; // Optional configInfo.depthStencilInfo.front = {}; // Optional
configInfo.depthStencilInfo.back = {}; // 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<uint32_t>(configInfo.dynamicStateEnables.size());
configInfo.dynamicStateInfo.flags = 0;
} }
std::vector<char> Pipeline::readFile(const std::string &filePath) std::vector<char> Pipeline::readFile(const std::string &filePath)
@ -165,25 +164,18 @@ namespace hk
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.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{}; VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2; pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages; pipelineInfo.pStages = shaderStages;
pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &configInfo.inputAssemblyInfo; pipelineInfo.pInputAssemblyState = &configInfo.inputAssemblyInfo;
pipelineInfo.pViewportState = &viewportInfo; pipelineInfo.pViewportState = &configInfo.viewportInfo;
pipelineInfo.pRasterizationState = &configInfo.rasterizationInfo; pipelineInfo.pRasterizationState = &configInfo.rasterizationInfo;
pipelineInfo.pMultisampleState = &configInfo.multisampleInfo; pipelineInfo.pMultisampleState = &configInfo.multisampleInfo;
pipelineInfo.pColorBlendState = &configInfo.colorBlendInfo; pipelineInfo.pColorBlendState = &configInfo.colorBlendInfo;
pipelineInfo.pDepthStencilState = &configInfo.depthStencilInfo; pipelineInfo.pDepthStencilState = &configInfo.depthStencilInfo;
pipelineInfo.pDynamicState = nullptr; pipelineInfo.pDynamicState = &configInfo.dynamicStateInfo;
pipelineInfo.layout = configInfo.pipelineLayout; pipelineInfo.layout = configInfo.pipelineLayout;
pipelineInfo.renderPass = configInfo.renderPass; pipelineInfo.renderPass = configInfo.renderPass;

View File

@ -10,14 +10,18 @@ namespace hk
{ {
struct PipelineConfigInfo struct PipelineConfigInfo
{ {
VkViewport viewport; PipelineConfigInfo(const PipelineConfigInfo&) = delete;
VkRect2D scissor; PipelineConfigInfo &operator=(const PipelineConfigInfo&) = delete;
VkPipelineViewportStateCreateInfo viewportInfo;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo; VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo;
VkPipelineRasterizationStateCreateInfo rasterizationInfo; VkPipelineRasterizationStateCreateInfo rasterizationInfo;
VkPipelineMultisampleStateCreateInfo multisampleInfo; VkPipelineMultisampleStateCreateInfo multisampleInfo;
VkPipelineColorBlendAttachmentState colorBlendAttachment; VkPipelineColorBlendAttachmentState colorBlendAttachment;
VkPipelineColorBlendStateCreateInfo colorBlendInfo; VkPipelineColorBlendStateCreateInfo colorBlendInfo;
VkPipelineDepthStencilStateCreateInfo depthStencilInfo; VkPipelineDepthStencilStateCreateInfo depthStencilInfo;
std::vector<VkDynamicState> dynamicStateEnables;
VkPipelineDynamicStateCreateInfo dynamicStateInfo;
VkPipelineLayout pipelineLayout = nullptr; VkPipelineLayout pipelineLayout = nullptr;
VkRenderPass renderPass = nullptr; VkRenderPass renderPass = nullptr;
uint32_t subpass = 0; uint32_t subpass = 0;
@ -38,7 +42,7 @@ namespace hk
void bind(VkCommandBuffer commandBuffer); void bind(VkCommandBuffer commandBuffer);
static PipelineConfigInfo defaultPipelineConfigInfo(uint32_t width, uint32_t height); static void defaultPipelineConfigInfo(PipelineConfigInfo& configInfo);
private: private:
static std::vector<char> readFile(const std::string &filePath); static std::vector<char> readFile(const std::string &filePath);

View File

@ -14,6 +14,19 @@ namespace hk
SwapChain::SwapChain(Device &deviceRef, VkExtent2D extent) SwapChain::SwapChain(Device &deviceRef, VkExtent2D extent)
: device{deviceRef}, windowExtent{extent} : device{deviceRef}, windowExtent{extent}
{
init();
}
SwapChain::SwapChain(Device &deviceRef, VkExtent2D extent, std::shared_ptr<SwapChain> previous)
: device{deviceRef}, windowExtent{extent}, oldSwapChain{previous}
{
init();
// clean up old swap chain
oldSwapChain = nullptr;
}
void SwapChain::init()
{ {
createSwapChain(); createSwapChain();
createImageViews(); createImageViews();
@ -179,7 +192,7 @@ namespace hk
createInfo.presentMode = presentMode; createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE; 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) if (vkCreateSwapchainKHR(device.device(), &createInfo, nullptr, &swapChain) != VK_SUCCESS)
{ {

View File

@ -6,6 +6,7 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
// std lib headers // std lib headers
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -18,6 +19,7 @@ namespace hk
static constexpr int MAX_FRAMES_IN_FLIGHT = 2; static constexpr int MAX_FRAMES_IN_FLIGHT = 2;
SwapChain(Device &deviceRef, VkExtent2D windowExtent); SwapChain(Device &deviceRef, VkExtent2D windowExtent);
SwapChain(Device &deviceRef, VkExtent2D windowExtent, std::shared_ptr<SwapChain> previous);
~SwapChain(); ~SwapChain();
SwapChain(const SwapChain &) = delete; SwapChain(const SwapChain &) = delete;
@ -42,6 +44,7 @@ namespace hk
VkResult submitCommandBuffers(const VkCommandBuffer *buffers, uint32_t *imageIndex); VkResult submitCommandBuffers(const VkCommandBuffer *buffers, uint32_t *imageIndex);
private: private:
void init();
void createSwapChain(); void createSwapChain();
void createImageViews(); void createImageViews();
void createDepthResources(); void createDepthResources();
@ -72,6 +75,7 @@ namespace hk
VkExtent2D windowExtent; VkExtent2D windowExtent;
VkSwapchainKHR swapChain; VkSwapchainKHR swapChain;
std::shared_ptr<SwapChain> oldSwapChain;
std::vector<VkSemaphore> imageAvailableSemaphores; std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores; std::vector<VkSemaphore> renderFinishedSemaphores;