Add doFrame function

This commit is contained in:
Grayson Riffe 2025-02-12 04:20:30 -06:00
parent ebe78cb4ca
commit c5e1a66e36
5 changed files with 92 additions and 9 deletions

View File

@ -19,8 +19,7 @@ namespace nf::client {
m_renderEngine = std::make_unique<render::RenderEngine>(std::move(windowFuture.get()), m_config.display);
while (m_running) {
NFLog("Client running...");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
m_renderEngine->doFrame();
}
inputThread.join();

View File

@ -107,11 +107,6 @@ namespace nf::client {
}
case WM_CLOSE:
DestroyWindow(hWnd);
NFLog("Window destroyed");
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
@ -127,4 +122,9 @@ namespace nf::client {
int width = cli.right - cli.left, height = cli.bottom - cli.top;
return { width, height };
}
Window::~Window() {
DestroyWindow(m_handle);
NFLog("Window destroyed");
}
}

View File

@ -14,6 +14,8 @@ namespace nf::client {
void setDisplay(DisplayConfig config);
void runLoop();
void show(bool show = true);
~Window();
private:
void registerWindowClass();
static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

View File

@ -281,11 +281,19 @@ namespace nf::client::render {
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &outputColorAttachmentReference;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo renderPassCI = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &outputColorAttachment;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 1;
renderPassCI.pDependencies = &dependency;
if (vkCreateRenderPass(m_device, &renderPassCI, nullptr, &m_renderPassOutput) != VK_SUCCESS)
NFError("Could not create Vulkan output render pass.");
@ -375,8 +383,7 @@ namespace nf::client::render {
framebufferCI.renderPass = m_renderPassOutput;
framebufferCI.attachmentCount = 1;
framebufferCI.pAttachments = &m_swapchainImageViews[i];
framebufferCI.width = m_display.width;
framebufferCI.height = m_display.height;
framebufferCI.width = m_display.width, framebufferCI.height = m_display.height;
framebufferCI.layers = 1;
if (vkCreateFramebuffer(m_device, &framebufferCI, nullptr, &m_swapchainFramebuffers[i]) != VK_SUCCESS)
@ -407,11 +414,84 @@ namespace nf::client::render {
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)
NFError("Could not create fence.");
}
void RenderEngine::doFrame() {
// First, wait for previous frame to complete
vkWaitForFences(m_device, 1, &m_fenceInFlight, VK_TRUE, UINT64_MAX);
vkResetFences(m_device, 1, &m_fenceInFlight);
// Get next swapchain image
uint32_t nextImageIndex = 0;
vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, m_semaphoreImageAvailable, nullptr, &nextImageIndex);
// Begin recording
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
if (vkBeginCommandBuffer(m_commandBuffer, &commandBufferBI) != VK_SUCCESS)
NFError("Could not begin recording command buffer.");
// Start the render pass
VkClearValue black = { {{0.0, 0.0, 0.0, 1.0}} };
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.clearValueCount = 1;
renderPassBI.pClearValues = &black;
vkCmdBeginRenderPass(m_commandBuffer, &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
// Bind output pipeline
vkCmdBindPipeline(m_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);
// Draw
vkCmdDraw(m_commandBuffer, 3, 1, 0, 0);
// End the render pass
vkCmdEndRenderPass(m_commandBuffer);
// Finish recording
if (vkEndCommandBuffer(m_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.pWaitDstStageMask = &waitStage;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &m_commandBuffer;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &m_semaphoreRenderFinished;
if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, m_fenceInFlight) != 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.swapchainCount = 1;
presentInfo.pSwapchains = &m_swapchain;
presentInfo.pImageIndices = &nextImageIndex;
vkQueuePresentKHR(m_queuePresent, &presentInfo);
}
RenderEngine::~RenderEngine() {
vkDeviceWaitIdle(m_device);
vkDestroyFence(m_device, m_fenceInFlight, nullptr);
vkDestroySemaphore(m_device, m_semaphoreRenderFinished, nullptr);
vkDestroySemaphore(m_device, m_semaphoreImageAvailable, nullptr);

View File

@ -9,6 +9,8 @@ namespace nf::client::render {
public:
RenderEngine(std::shared_ptr<Window> window, DisplayConfig display);
void doFrame();
~RenderEngine();
private:
void createInstance();