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",
"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"
}
}

Binary file not shown.

View File

@ -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<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();
}
@ -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)
{
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<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]);
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!");

View File

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

View File

@ -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<float>(width);
configInfo.viewport.height = static_cast<float>(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<uint32_t>(configInfo.dynamicStateEnables.size());
configInfo.dynamicStateInfo.flags = 0;
}
std::vector<char> 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;

View File

@ -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<VkDynamicState> 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<char> readFile(const std::string &filePath);

View File

@ -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<SwapChain> 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)
{

View File

@ -6,6 +6,7 @@
#include <vulkan/vulkan.h>
// std lib headers
#include <memory>
#include <string>
#include <vector>
@ -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<SwapChain> 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<SwapChain> oldSwapChain;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;