Two frames in flight
This commit is contained in:
parent
f9232f314b
commit
3088a42a07
@ -26,10 +26,9 @@ namespace nf::client::render {
|
||||
, m_pipelineLayoutOutput()
|
||||
, m_pipelineOutput()
|
||||
, m_commandPool()
|
||||
, m_commandBuffer()
|
||||
, m_semaphoreImageAvailable()
|
||||
, m_semaphoreRenderFinished()
|
||||
, m_fenceInFlight()
|
||||
, m_numFramesInFlight(2)
|
||||
, m_frameExecutors()
|
||||
, m_currentFrameExecutor()
|
||||
{
|
||||
NFLog("Initializing render engine");
|
||||
m_window->setDisplay(m_display);
|
||||
@ -41,8 +40,7 @@ namespace nf::client::render {
|
||||
createSwapchain();
|
||||
createOutputRenderPass();
|
||||
createOutputPipeline();
|
||||
createCommandBuffer();
|
||||
createSynchronizationObjects();
|
||||
createFrameExecutors();
|
||||
|
||||
m_window->show();
|
||||
}
|
||||
@ -391,7 +389,7 @@ namespace nf::client::render {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderEngine::createCommandBuffer() {
|
||||
void RenderEngine::createFrameExecutors() {
|
||||
VkCommandPoolCreateInfo commandPoolCI = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
||||
commandPoolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
commandPoolCI.queueFamilyIndex = m_queueFIGraphics;
|
||||
@ -399,39 +397,43 @@ namespace nf::client::render {
|
||||
if (vkCreateCommandPool(m_device, &commandPoolCI, nullptr, &m_commandPool) != VK_SUCCESS)
|
||||
NFError("Could not create command pool.");
|
||||
|
||||
m_frameExecutors.resize(m_numFramesInFlight);
|
||||
for (int i = 0; i < m_frameExecutors.size(); i++) {
|
||||
VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
commandBufferAI.commandPool = m_commandPool;
|
||||
commandBufferAI.commandBufferCount = 1;
|
||||
|
||||
if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &m_commandBuffer) != VK_SUCCESS)
|
||||
if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &m_frameExecutors[i].commandBuffer) != VK_SUCCESS)
|
||||
NFError("Could not create command buffer.");
|
||||
}
|
||||
|
||||
void RenderEngine::createSynchronizationObjects() {
|
||||
VkSemaphoreCreateInfo semaphoreCI = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
if (vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_semaphoreImageAvailable) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_semaphoreRenderFinished) != VK_SUCCESS)
|
||||
if (vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_frameExecutors[i].semaphoreImageAvailable) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(m_device, &semaphoreCI, nullptr, &m_frameExecutors[i].semaphoreRenderFinished) != VK_SUCCESS)
|
||||
NFError("Could not create semaphore.");
|
||||
|
||||
VkFenceCreateInfo fenceCI = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||
fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
if (vkCreateFence(m_device, &fenceCI, nullptr, &m_fenceInFlight) != VK_SUCCESS)
|
||||
if (vkCreateFence(m_device, &fenceCI, nullptr, &m_frameExecutors[i].fenceFrameInFlight) != VK_SUCCESS)
|
||||
NFError("Could not create fence.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderEngine::doFrame() {
|
||||
// Get current frame executor
|
||||
auto& [commandBuffer, semaphoreImageAvailable, semaphoreRenderFinished, fenceFrameInFlight] = m_frameExecutors[m_currentFrameExecutor];
|
||||
|
||||
// First, wait for previous frame to complete
|
||||
vkWaitForFences(m_device, 1, &m_fenceInFlight, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(m_device, 1, &m_fenceInFlight);
|
||||
vkWaitForFences(m_device, 1, &fenceFrameInFlight, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(m_device, 1, &fenceFrameInFlight);
|
||||
|
||||
// Get next swapchain image
|
||||
uint32_t nextImageIndex = 0;
|
||||
vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_semaphoreImageAvailable, nullptr, &nextImageIndex);
|
||||
vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, semaphoreImageAvailable, nullptr, &nextImageIndex);
|
||||
|
||||
// Begin recording
|
||||
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
|
||||
if (vkBeginCommandBuffer(m_commandBuffer, &commandBufferBI) != VK_SUCCESS)
|
||||
if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS)
|
||||
NFError("Could not begin recording command buffer.");
|
||||
|
||||
// Start the render pass
|
||||
@ -442,59 +444,63 @@ namespace nf::client::render {
|
||||
renderPassBI.renderArea.extent = { m_display.width, m_display.height };
|
||||
renderPassBI.clearValueCount = 1;
|
||||
renderPassBI.pClearValues = &black;
|
||||
vkCmdBeginRenderPass(m_commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
// Bind output pipeline
|
||||
vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutput);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineOutput);
|
||||
|
||||
// Set viewport
|
||||
VkViewport viewport = {};
|
||||
viewport.width = static_cast<float>(m_display.width), viewport.height = static_cast<float>(m_display.height);
|
||||
viewport.maxDepth = 1.0;
|
||||
vkCmdSetViewport(m_commandBuffer, 0, 1, &viewport);
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
|
||||
// Draw
|
||||
vkCmdDraw(m_commandBuffer, 3, 1, 0, 0);
|
||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||
|
||||
// End the render pass
|
||||
vkCmdEndRenderPass(m_commandBuffer);
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
|
||||
// Finish recording
|
||||
if (vkEndCommandBuffer(m_commandBuffer) != VK_SUCCESS)
|
||||
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
|
||||
NFError("Could not end command buffer.");
|
||||
|
||||
// Submit to graphics queue
|
||||
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = &m_semaphoreImageAvailable;
|
||||
submitInfo.pWaitSemaphores = &semaphoreImageAvailable;
|
||||
submitInfo.pWaitDstStageMask = &waitStage;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &m_commandBuffer;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = &m_semaphoreRenderFinished;
|
||||
submitInfo.pSignalSemaphores = &semaphoreRenderFinished;
|
||||
|
||||
if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, m_fenceInFlight) != VK_SUCCESS)
|
||||
if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, fenceFrameInFlight) != VK_SUCCESS)
|
||||
NFError("Could not submit to Vulkan queue.");
|
||||
|
||||
// And present!
|
||||
VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pWaitSemaphores = &m_semaphoreRenderFinished;
|
||||
presentInfo.pWaitSemaphores = &semaphoreRenderFinished;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &m_swapchain;
|
||||
presentInfo.pImageIndices = &nextImageIndex;
|
||||
|
||||
vkQueuePresentKHR(m_queuePresent, &presentInfo);
|
||||
}
|
||||
|
||||
// Advance to next frame executor
|
||||
m_currentFrameExecutor = (m_currentFrameExecutor + 1) % m_numFramesInFlight;
|
||||
}
|
||||
|
||||
RenderEngine::~RenderEngine() {
|
||||
vkDeviceWaitIdle(m_device);
|
||||
|
||||
vkDestroyFence(m_device, m_fenceInFlight, nullptr);
|
||||
vkDestroySemaphore(m_device, m_semaphoreRenderFinished, nullptr);
|
||||
vkDestroySemaphore(m_device, m_semaphoreImageAvailable, nullptr);
|
||||
for (int i = 0; i < m_frameExecutors.size(); i++) {
|
||||
vkDestroyFence(m_device, m_frameExecutors[i].fenceFrameInFlight, nullptr);
|
||||
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreRenderFinished, nullptr);
|
||||
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr);
|
||||
}
|
||||
|
||||
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
||||
|
||||
|
@ -5,6 +5,12 @@
|
||||
#include "nf/config.h"
|
||||
|
||||
namespace nf::client::render {
|
||||
struct FrameExecutor {
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkSemaphore semaphoreImageAvailable, semaphoreRenderFinished;
|
||||
VkFence fenceFrameInFlight;
|
||||
};
|
||||
|
||||
class RenderEngine {
|
||||
public:
|
||||
RenderEngine(std::shared_ptr<Window> window, DisplayConfig display);
|
||||
@ -20,8 +26,7 @@ namespace nf::client::render {
|
||||
void createSwapchain();
|
||||
void createOutputRenderPass();
|
||||
void createOutputPipeline();
|
||||
void createCommandBuffer();
|
||||
void createSynchronizationObjects();
|
||||
void createFrameExecutors();
|
||||
|
||||
std::shared_ptr<Window> m_window;
|
||||
DisplayConfig m_display;
|
||||
@ -46,13 +51,10 @@ namespace nf::client::render {
|
||||
VkPipelineLayout m_pipelineLayoutOutput;
|
||||
VkPipeline m_pipelineOutput;
|
||||
|
||||
// Command buffers
|
||||
// Execution objects
|
||||
VkCommandPool m_commandPool;
|
||||
VkCommandBuffer m_commandBuffer;
|
||||
|
||||
// Synchronization objects
|
||||
VkSemaphore m_semaphoreImageAvailable;
|
||||
VkSemaphore m_semaphoreRenderFinished;
|
||||
VkFence m_fenceInFlight;
|
||||
const uint32_t m_numFramesInFlight;
|
||||
std::vector<FrameExecutor> m_frameExecutors;
|
||||
uint32_t m_currentFrameExecutor;
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user