diff --git a/src/main.cpp b/src/main.cpp index d395d07..f7acb37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,17 +56,23 @@ class VulkanApp { vk::Queue mGraphicsQueue; vk::Queue mPresentQueue; - vk::UniqueSwapchainKHR mSwapChain; - std::vector mSwapChainImages; - vk::Format mSwapChainImageFormat; - vk::Extent2D mSwapChainExtent; - std::vector mSwapChainImageViews; + vk::UniqueSwapchainKHR mSwapChain; + std::vector mSwapChainImages; + vk::Format mSwapChainImageFormat; + vk::Extent2D mSwapChainExtent; + std::vector mSwapChainImageViews; + std::vector mSwapChainFramebuffers; vk::UniqueRenderPass mRenderPass; vk::UniquePipelineLayout mPipelineLayout; vk::UniquePipeline mGraphicsPipeline; - std::vector mSwapChainFramebuffers; + vk::UniqueCommandPool mCommandPool; + vk::UniqueCommandBuffer mCommandBuffer; + + vk::UniqueSemaphore mImageAvailableSemaphore; + vk::UniqueSemaphore mRenderFinishedSemaphore; + vk::UniqueFence mInFlightFence; struct QueueFamilyIndices { std::optional graphics_family; @@ -120,10 +126,18 @@ class VulkanApp { createRenderPass(); createGraphicsPipeline(); createFramebuffers(); + createCommandPool(); + createCommandBuffer(); + createSyncObjects(); } fn mainLoop() -> void { - while (!mWindow->shouldClose()) { vkfw::waitEvents(); } + while (!mWindow->shouldClose()) { + vkfw::waitEvents(); + drawFrame(); + } + + mDevice->waitIdle(); } fn createInstance() -> void { @@ -464,6 +478,123 @@ class VulkanApp { } } + fn createCommandPool() -> void { + QueueFamilyIndices queueFamilyIndices = findQueueFamilies(mPhysicalDevice); + + vk::CommandPoolCreateInfo poolInfo { + .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer, + .queueFamilyIndex = queueFamilyIndices.graphics_family.value(), + }; + + mCommandPool = mDevice->createCommandPoolUnique(poolInfo); + } + + fn createCommandBuffer() -> void { + vk::CommandBufferAllocateInfo allocInfo { + .commandPool = mCommandPool.get(), + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; + + mCommandBuffer = std::move(mDevice->allocateCommandBuffersUnique(allocInfo)[0]); + } + + fn recordCommandBuffer(vk::CommandBuffer commandBuffer, u32 imageIndex) -> void { + // might break + vk::CommandBufferBeginInfo beginInfo {}; + + commandBuffer.begin(beginInfo); + + vk::ClearValue clearColor { { std::array { 0.0F, 0.0F, 0.0F, 1.0F } } }; + + vk::RenderPassBeginInfo renderPassInfo { + .renderPass = mRenderPass.get(), + .framebuffer = mSwapChainFramebuffers[imageIndex].get(), + .renderArea = { .offset = { 0, 0 }, .extent = mSwapChainExtent }, + .clearValueCount = 1, + .pClearValues = &clearColor, + }; + + commandBuffer.beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); + + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, mGraphicsPipeline.get()); + + vk::Viewport viewport { + .x = 0.0F, + .y = 0.0F, + .width = static_cast(mSwapChainExtent.width), + .height = static_cast(mSwapChainExtent.height), + .minDepth = 0.0F, + .maxDepth = 1.0F, + }; + + commandBuffer.setViewport(0, viewport); + + vk::Rect2D scissor { + .offset = { 0, 0 }, + .extent = mSwapChainExtent, + }; + + commandBuffer.setScissor(0, scissor); + + commandBuffer.draw(3, 1, 0, 0); + + commandBuffer.endRenderPass(); + + commandBuffer.end(); + } + + fn createSyncObjects() -> void { + vk::SemaphoreCreateInfo semaphoreInfo {}; + vk::FenceCreateInfo fenceInfo { .flags = vk::FenceCreateFlagBits::eSignaled }; + + mImageAvailableSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo); + mRenderFinishedSemaphore = mDevice->createSemaphoreUnique(semaphoreInfo); + mInFlightFence = mDevice->createFenceUnique(fenceInfo); + } + + fn drawFrame() -> void { + vk::Result result = mDevice->waitForFences(mInFlightFence.get(), vk::Bool32(vk::True), UINT64_MAX); + + if (result != vk::Result::eSuccess) + throw std::runtime_error("Failed to wait for fences!"); + + mDevice->resetFences(mInFlightFence.get()); + + u32 imageIndex = + mDevice->acquireNextImageKHR(mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphore.get(), nullptr) + .value; + + mCommandBuffer->reset(vk::CommandBufferResetFlagBits::eReleaseResources); + recordCommandBuffer(mCommandBuffer.get(), imageIndex); + + std::array waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput }; + + vk::SubmitInfo submitInfo { + .waitSemaphoreCount = 1, + .pWaitSemaphores = &mImageAvailableSemaphore.get(), + .pWaitDstStageMask = waitStages.data(), + .commandBufferCount = 1, + .pCommandBuffers = &mCommandBuffer.get(), + .signalSemaphoreCount = 1, + .pSignalSemaphores = &mRenderFinishedSemaphore.get(), + }; + + mGraphicsQueue.submit(submitInfo, mInFlightFence.get()); + + vk::PresentInfoKHR presentInfo { + .waitSemaphoreCount = 1, + .pWaitSemaphores = &mRenderFinishedSemaphore.get(), + .swapchainCount = 1, + .pSwapchains = &mSwapChain.get(), + .pImageIndices = &imageIndex, + }; + + vk::Result presentResult = mPresentQueue.presentKHR(presentInfo); + if (presentResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to present swap chain image!"); + } + fn createShaderModule(const std::vector& code) -> vk::UniqueShaderModule { vk::ShaderModuleCreateInfo createInfo { .codeSize = code.size(), .pCode = std::bit_cast(code.data()) };