From c5e1a66e362e5321e97946af81996ef47791d11c Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Wed, 12 Feb 2025 04:20:30 -0600 Subject: [PATCH] Add doFrame function --- NothinFancy/src/client/Client.cpp | 3 +- NothinFancy/src/client/Window.cpp | 10 +-- NothinFancy/src/client/Window.h | 2 + .../src/client/render/RenderEngine.cpp | 84 ++++++++++++++++++- NothinFancy/src/client/render/RenderEngine.h | 2 + 5 files changed, 92 insertions(+), 9 deletions(-) diff --git a/NothinFancy/src/client/Client.cpp b/NothinFancy/src/client/Client.cpp index 236b665..d4739b9 100644 --- a/NothinFancy/src/client/Client.cpp +++ b/NothinFancy/src/client/Client.cpp @@ -19,8 +19,7 @@ namespace nf::client { m_renderEngine = std::make_unique(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(); diff --git a/NothinFancy/src/client/Window.cpp b/NothinFancy/src/client/Window.cpp index 9571056..5bfa33f 100644 --- a/NothinFancy/src/client/Window.cpp +++ b/NothinFancy/src/client/Window.cpp @@ -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"); + } } diff --git a/NothinFancy/src/client/Window.h b/NothinFancy/src/client/Window.h index ecbb59b..4c9a6d3 100644 --- a/NothinFancy/src/client/Window.h +++ b/NothinFancy/src/client/Window.h @@ -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); diff --git a/NothinFancy/src/client/render/RenderEngine.cpp b/NothinFancy/src/client/render/RenderEngine.cpp index c003ad1..74840d0 100644 --- a/NothinFancy/src/client/render/RenderEngine.cpp +++ b/NothinFancy/src/client/render/RenderEngine.cpp @@ -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(m_display.width), viewport.height = static_cast(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); diff --git a/NothinFancy/src/client/render/RenderEngine.h b/NothinFancy/src/client/render/RenderEngine.h index 22816d4..5fdde7c 100644 --- a/NothinFancy/src/client/render/RenderEngine.h +++ b/NothinFancy/src/client/render/RenderEngine.h @@ -9,6 +9,8 @@ namespace nf::client::render { public: RenderEngine(std::shared_ptr window, DisplayConfig display); + void doFrame(); + ~RenderEngine(); private: void createInstance();