Add swapchain recreation
This commit is contained in:
parent
3088a42a07
commit
798be67cc5
@ -29,6 +29,8 @@ namespace nf::client {
|
||||
|
||||
void Window::setDisplay(DisplayConfig& config) {
|
||||
NFLog("Setting window display");
|
||||
bool wasShown = IsWindowVisible(m_handle);
|
||||
show(false);
|
||||
|
||||
// TODO: Only use "active" monitor when starting windowed
|
||||
POINT cursor = {};
|
||||
@ -55,12 +57,15 @@ namespace nf::client {
|
||||
SetWindowLongPtr(m_handle, GWL_STYLE, m_styleFullscreen);
|
||||
windowX = monitorX, windowY = monitorY;
|
||||
windowWidth = monitorWidth, windowHeight = monitorHeight;
|
||||
m_currentWidth = windowWidth, m_currentHeight = windowHeight;
|
||||
config.width = windowWidth, config.height = windowHeight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetWindowPos(m_handle, nullptr, windowX, windowY, windowWidth, windowHeight, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
show(wasShown);
|
||||
}
|
||||
|
||||
void Window::runLoop() {
|
||||
|
@ -20,6 +20,7 @@ namespace nf::client::render {
|
||||
, m_renderPassOutput()
|
||||
, m_swapchain()
|
||||
, m_swapchainImageFormat()
|
||||
, m_swapchainExtent()
|
||||
, m_swapchainImages()
|
||||
, m_swapchainImageViews()
|
||||
, m_swapchainFramebuffers()
|
||||
@ -39,6 +40,7 @@ namespace nf::client::render {
|
||||
createDevice();
|
||||
createSwapchain();
|
||||
createOutputRenderPass();
|
||||
createSwapchainFramebuffers();
|
||||
createOutputPipeline();
|
||||
createFrameExecutors();
|
||||
|
||||
@ -209,9 +211,9 @@ namespace nf::client::render {
|
||||
if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||
chosenPresentMode = presentModes[i];
|
||||
|
||||
VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent;
|
||||
if (swapchainExtent.width == std::numeric_limits<uint32_t>::max())
|
||||
swapchainExtent.width = m_display.width, swapchainExtent.height = m_display.height;
|
||||
m_swapchainExtent = surfaceCapabilities.currentExtent;
|
||||
if (m_swapchainExtent.width == std::numeric_limits<uint32_t>::max())
|
||||
m_swapchainExtent = { m_display.width, m_display.height };
|
||||
|
||||
uint32_t numRequestedImages = surfaceCapabilities.minImageCount + (surfaceCapabilities.minImageCount != surfaceCapabilities.maxImageCount ? 1 : 0);
|
||||
|
||||
@ -220,7 +222,7 @@ namespace nf::client::render {
|
||||
swapchainCI.minImageCount = numRequestedImages;
|
||||
swapchainCI.imageFormat = m_swapchainImageFormat = chosenSurfaceFormat.format;
|
||||
swapchainCI.imageColorSpace = chosenSurfaceFormat.colorSpace;
|
||||
swapchainCI.imageExtent = swapchainExtent;
|
||||
swapchainCI.imageExtent = m_swapchainExtent;
|
||||
swapchainCI.imageArrayLayers = 1;
|
||||
swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
@ -297,6 +299,22 @@ namespace nf::client::render {
|
||||
NFError("Could not create Vulkan output render pass.");
|
||||
}
|
||||
|
||||
void RenderEngine::createSwapchainFramebuffers() {
|
||||
// TODO: Won't need these forever
|
||||
m_swapchainFramebuffers.resize(m_swapchainImageViews.size());
|
||||
for (int i = 0; i < m_swapchainImageViews.size(); i++) {
|
||||
VkFramebufferCreateInfo framebufferCI = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
framebufferCI.renderPass = m_renderPassOutput;
|
||||
framebufferCI.attachmentCount = 1;
|
||||
framebufferCI.pAttachments = &m_swapchainImageViews[i];
|
||||
framebufferCI.width = m_swapchainExtent.width, framebufferCI.height = m_swapchainExtent.height;
|
||||
framebufferCI.layers = 1;
|
||||
|
||||
if (vkCreateFramebuffer(m_device, &framebufferCI, nullptr, &m_swapchainFramebuffers[i]) != VK_SUCCESS)
|
||||
NFError("Could not create framebuffer.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderEngine::createOutputPipeline() {
|
||||
// First, create shader modules
|
||||
std::string outputShaderVertexBinary, outputShaderFragmentBinary;
|
||||
@ -315,10 +333,10 @@ namespace nf::client::render {
|
||||
outputShaderStages[1].module = outputShaderFragmentModule.getHandle();
|
||||
|
||||
// Specify dynamic state
|
||||
VkDynamicState dynamicState = VK_DYNAMIC_STATE_VIEWPORT;
|
||||
std::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineDynamicStateCreateInfo dynamicStateCI = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
dynamicStateCI.dynamicStateCount = 1;
|
||||
dynamicStateCI.pDynamicStates = &dynamicState;
|
||||
dynamicStateCI.dynamicStateCount = dynamicStates.size();
|
||||
dynamicStateCI.pDynamicStates = dynamicStates.data();
|
||||
|
||||
// Specify vertex input state
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
@ -328,11 +346,9 @@ namespace nf::client::render {
|
||||
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
// Specify viewport state
|
||||
VkRect2D scissor = { {0, 0}, {m_display.width, m_display.height} };
|
||||
VkPipelineViewportStateCreateInfo viewportStateCI = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
viewportStateCI.viewportCount = 1;
|
||||
viewportStateCI.scissorCount = 1;
|
||||
viewportStateCI.pScissors = &scissor;
|
||||
|
||||
// Specify rasterization state
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationCI = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
@ -373,20 +389,6 @@ namespace nf::client::render {
|
||||
|
||||
if (vkCreateGraphicsPipelines(m_device, nullptr, 1, &pipelineCI, nullptr, &m_pipelineOutput) != VK_SUCCESS)
|
||||
NFError("Could not create graphics pipeline.");
|
||||
|
||||
// TODO: For now, create swapchain framebuffers
|
||||
m_swapchainFramebuffers.resize(m_swapchainImageViews.size());
|
||||
for (int i = 0; i < m_swapchainImageViews.size(); i++) {
|
||||
VkFramebufferCreateInfo framebufferCI = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
framebufferCI.renderPass = m_renderPassOutput;
|
||||
framebufferCI.attachmentCount = 1;
|
||||
framebufferCI.pAttachments = &m_swapchainImageViews[i];
|
||||
framebufferCI.width = m_display.width, framebufferCI.height = m_display.height;
|
||||
framebufferCI.layers = 1;
|
||||
|
||||
if (vkCreateFramebuffer(m_device, &framebufferCI, nullptr, &m_swapchainFramebuffers[i]) != VK_SUCCESS)
|
||||
NFError("Could not create framebuffer.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderEngine::createFrameExecutors() {
|
||||
@ -424,11 +426,19 @@ namespace nf::client::render {
|
||||
|
||||
// First, wait for previous frame to complete
|
||||
vkWaitForFences(m_device, 1, &fenceFrameInFlight, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(m_device, 1, &fenceFrameInFlight);
|
||||
|
||||
// Get next swapchain image
|
||||
// Get next swapchain image and recreate if necessary
|
||||
uint32_t nextImageIndex = 0;
|
||||
vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, semaphoreImageAvailable, nullptr, &nextImageIndex);
|
||||
VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, semaphoreImageAvailable, nullptr, &nextImageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
recreateSwapchain();
|
||||
return;
|
||||
}
|
||||
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
|
||||
NFError("Could not aquire next swapchain image.");
|
||||
|
||||
// Reset fence for this frame
|
||||
vkResetFences(m_device, 1, &fenceFrameInFlight);
|
||||
|
||||
// Begin recording
|
||||
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
@ -441,7 +451,7 @@ namespace nf::client::render {
|
||||
VkRenderPassBeginInfo renderPassBI = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
renderPassBI.renderPass = m_renderPassOutput;
|
||||
renderPassBI.framebuffer = m_swapchainFramebuffers[nextImageIndex];
|
||||
renderPassBI.renderArea.extent = { m_display.width, m_display.height };
|
||||
renderPassBI.renderArea.extent = m_swapchainExtent;
|
||||
renderPassBI.clearValueCount = 1;
|
||||
renderPassBI.pClearValues = &black;
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
|
||||
@ -449,11 +459,13 @@ namespace nf::client::render {
|
||||
// Bind output pipeline
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutput);
|
||||
|
||||
// Set viewport
|
||||
// Set viewport and scissor
|
||||
VkViewport viewport = {};
|
||||
viewport.width = static_cast<float>(m_display.width), viewport.height = static_cast<float>(m_display.height);
|
||||
viewport.width = static_cast<float>(m_swapchainExtent.width), viewport.height = static_cast<float>(m_swapchainExtent.height);
|
||||
viewport.maxDepth = 1.0;
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
VkRect2D scissor = { {}, m_swapchainExtent };
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
// Draw
|
||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||
@ -487,14 +499,46 @@ namespace nf::client::render {
|
||||
presentInfo.pSwapchains = &m_swapchain;
|
||||
presentInfo.pImageIndices = &nextImageIndex;
|
||||
|
||||
vkQueuePresentKHR(m_queuePresent, &presentInfo);
|
||||
result = vkQueuePresentKHR(m_queuePresent, &presentInfo);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
recreateSwapchain();
|
||||
else if (result != VK_SUCCESS)
|
||||
NFError("Could not present image.");
|
||||
|
||||
// Advance to next frame executor
|
||||
m_currentFrameExecutor = (m_currentFrameExecutor + 1) % m_numFramesInFlight;
|
||||
}
|
||||
|
||||
RenderEngine::~RenderEngine() {
|
||||
void RenderEngine::setDisplay(DisplayConfig config) {
|
||||
m_display = config;
|
||||
m_window->setDisplay(m_display);
|
||||
}
|
||||
|
||||
void RenderEngine::recreateSwapchain() {
|
||||
waitIdle();
|
||||
|
||||
destroySwapchain();
|
||||
|
||||
createSwapchain();
|
||||
createSwapchainFramebuffers();
|
||||
}
|
||||
|
||||
void RenderEngine::destroySwapchain() {
|
||||
for (int i = 0; i < m_swapchainFramebuffers.size(); i++)
|
||||
vkDestroyFramebuffer(m_device, m_swapchainFramebuffers[i], nullptr);
|
||||
|
||||
for (int i = 0; i < m_swapchainImageViews.size(); i++)
|
||||
vkDestroyImageView(m_device, m_swapchainImageViews[i], nullptr);
|
||||
|
||||
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
|
||||
}
|
||||
|
||||
void RenderEngine::waitIdle() {
|
||||
vkDeviceWaitIdle(m_device);
|
||||
}
|
||||
|
||||
RenderEngine::~RenderEngine() {
|
||||
waitIdle();
|
||||
|
||||
for (int i = 0; i < m_frameExecutors.size(); i++) {
|
||||
vkDestroyFence(m_device, m_frameExecutors[i].fenceFrameInFlight, nullptr);
|
||||
@ -502,19 +546,11 @@ namespace nf::client::render {
|
||||
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr);
|
||||
}
|
||||
|
||||
destroySwapchain();
|
||||
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
||||
|
||||
for (int i = 0; i < m_swapchainFramebuffers.size(); i++)
|
||||
vkDestroyFramebuffer(m_device, m_swapchainFramebuffers[i], nullptr);
|
||||
|
||||
vkDestroyPipeline(m_device, m_pipelineOutput, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayoutOutput, nullptr);
|
||||
vkDestroyRenderPass(m_device, m_renderPassOutput, nullptr);
|
||||
|
||||
for (int i = 0; i < m_swapchainImageViews.size(); i++)
|
||||
vkDestroyImageView(m_device, m_swapchainImageViews[i], nullptr);
|
||||
|
||||
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
|
||||
vkDestroyDevice(m_device, nullptr);
|
||||
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
|
||||
vkDestroyInstance(m_instance, nullptr);
|
||||
|
@ -16,6 +16,7 @@ namespace nf::client::render {
|
||||
RenderEngine(std::shared_ptr<Window> window, DisplayConfig display);
|
||||
|
||||
void doFrame();
|
||||
void setDisplay(DisplayConfig config);
|
||||
|
||||
~RenderEngine();
|
||||
private:
|
||||
@ -25,9 +26,15 @@ namespace nf::client::render {
|
||||
void createDevice();
|
||||
void createSwapchain();
|
||||
void createOutputRenderPass();
|
||||
void createSwapchainFramebuffers();
|
||||
void createOutputPipeline();
|
||||
void createFrameExecutors();
|
||||
|
||||
void recreateSwapchain();
|
||||
void destroySwapchain();
|
||||
|
||||
void waitIdle();
|
||||
|
||||
std::shared_ptr<Window> m_window;
|
||||
DisplayConfig m_display;
|
||||
|
||||
@ -43,6 +50,7 @@ namespace nf::client::render {
|
||||
// Swapchain
|
||||
VkSwapchainKHR m_swapchain;
|
||||
VkFormat m_swapchainImageFormat;
|
||||
VkExtent2D m_swapchainExtent;
|
||||
std::vector<VkImage> m_swapchainImages;
|
||||
std::vector<VkImageView> m_swapchainImageViews;
|
||||
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
||||
|
Loading…
x
Reference in New Issue
Block a user