Dynamic window resizing

This commit is contained in:
2026-02-20 21:25:33 +00:00
parent e4124c0aaf
commit 11783743de
9 changed files with 143 additions and 60 deletions

View File

@@ -7,7 +7,7 @@ namespace cve {
FirstApp::FirstApp() {
loadModels();
createPipelineLayout();
createPipeline();
recreateSwapChain();
createCommandBuffers();
}
@@ -48,8 +48,12 @@ namespace cve {
}
void FirstApp::createPipeline() {
auto pipelineConfig = CvePipeline::defaultPipelineConfigInfo(cveSwapChain.width(), cveSwapChain.height());
pipelineConfig.renderPass = cveSwapChain.getRenderPass();
assert(cveSwapChain != nullptr && "Cannot create pipeline before swap chain");
assert(pipelineLayout != nullptr && "Cannot create pipeline before pipeline layout");
PipelineConfigInfo pipelineConfig{};
CvePipeline::defaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.renderPass = cveSwapChain->getRenderPass();
pipelineConfig.pipelineLayout = pipelineLayout;
cvePipeline = std::make_unique<CvePipeline>(
cveDevice,
@@ -59,8 +63,31 @@ namespace cve {
);
}
void FirstApp::recreateSwapChain() {
auto extent = cveWindow.getExtent();
while (extent.width == 0 || extent.height == 0) {
extent = cveWindow.getExtent();
glfwWaitEvents();
}
vkDeviceWaitIdle(cveDevice.device());
if (cveSwapChain == nullptr) {
cveSwapChain = std::make_unique<CveSwapChain>(cveDevice, extent);
} else {
cveSwapChain = std::make_unique<CveSwapChain>(cveDevice, extent, std::move(cveSwapChain));
if (cveSwapChain->imageCount() != commandBuffers.size()) {
freeCommandBuffers();
createCommandBuffers();
}
}
// Check if render pass is compatible
createPipeline();
}
void FirstApp::createCommandBuffers() {
commandBuffers.resize(cveSwapChain.imageCount());
commandBuffers.resize(cveSwapChain->imageCount());
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -72,50 +99,78 @@ namespace cve {
VK_SUCCESS) {
throw std::runtime_error("Failed to allocate command buffers");
}
}
for (int i=0; i < commandBuffers.size(); i++) {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
void FirstApp::freeCommandBuffers() {
vkFreeCommandBuffers(cveDevice.device(), cveDevice.getCommandPool(),
static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
commandBuffers.clear();
}
if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("Failed to begin command buffer recording");
}
void FirstApp::recordCommandBuffer(int imageIndex) {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = cveSwapChain.getRenderPass();
renderPassInfo.framebuffer = cveSwapChain.getFrameBuffer(i);
if (vkBeginCommandBuffer(commandBuffers[imageIndex], &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("Failed to begin command buffer recording");
}
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = cveSwapChain.getSwapChainExtent();
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = cveSwapChain->getRenderPass();
renderPassInfo.framebuffer = cveSwapChain->getFrameBuffer(imageIndex);
std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = {0.1f, 0.1f, 0.1f, 1.0f};
clearValues[1].depthStencil = {1.0f, 0};
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = cveSwapChain->getSwapChainExtent();
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = {0.1f, 0.1f, 0.1f, 1.0f};
clearValues[1].depthStencil = {1.0f, 0};
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
cvePipeline->bind(commandBuffers[i]);
cveModel->bind(commandBuffers[i]);
cveModel->draw(commandBuffers[i]);
vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(commandBuffers[i]);
if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to record command buffer!");
}
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(cveSwapChain->getSwapChainExtent().width);
viewport.height = static_cast<float>(cveSwapChain->getSwapChainExtent().height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{{0, 0}, cveSwapChain->getSwapChainExtent()};
vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport);
vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor);
cvePipeline->bind(commandBuffers[imageIndex]);
cveModel->bind(commandBuffers[imageIndex]);
cveModel->draw(commandBuffers[imageIndex]);
vkCmdEndRenderPass(commandBuffers[imageIndex]);
if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) {
throw std::runtime_error("Failed to record command buffer!");
}
}
void FirstApp::drawFrame() {
uint32_t imageIndex;
auto result = cveSwapChain.acquireNextImage(&imageIndex);
auto result = cveSwapChain->acquireNextImage(&imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain();
return;
}
if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
throw std::runtime_error("Failed to acquire swap chain image!");
}
result = cveSwapChain.submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex);
recordCommandBuffer(imageIndex);
result = cveSwapChain->submitCommandBuffers(&commandBuffers[imageIndex], &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || cveWindow.wasWindowResized()) {
cveWindow.resetWindowResizedFlag();
recreateSwapChain();
return;
}
if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to present swap chain image!");
}