From 14b1d7d8a882028fd35a902ab2f8b3bf3070269b Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Sun, 20 Aug 2023 23:01:12 -0700 Subject: [PATCH] Add display-shader presentation Uses the graphics pipeline to both blit and transpose the 3ds-formatted textures. Does not read from the actual texture just yet since we dont write to the descriptor just yet. Some other patterns need to line up before then. --- include/renderer_vk/renderer_vk.hpp | 10 ++- src/core/renderer_vk/renderer_vk.cpp | 109 +++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/include/renderer_vk/renderer_vk.hpp b/include/renderer_vk/renderer_vk.hpp index e93a97b1..d2723e35 100644 --- a/include/renderer_vk/renderer_vk.hpp +++ b/include/renderer_vk/renderer_vk.hpp @@ -5,6 +5,7 @@ #include "renderer.hpp" #include "vk_api.hpp" #include "vk_descriptor_heap.hpp" +#include "vk_descriptor_update_batch.hpp" class GPU; @@ -72,7 +73,7 @@ class RendererVK final : public Renderer { } }; // Hash(loc, size, format) -> Texture - std::map textureCache; + std::map textureCache; static u32 colorBufferHash(u32 loc, u32 size, PICA::ColorFmt format); static u32 depthBufferHash(u32 loc, u32 size, PICA::DepthFmt format); @@ -82,6 +83,8 @@ class RendererVK final : public Renderer { // Framebuffer for the top/bottom image std::vector screenTexture = {}; + std::vector screenTextureViews = {}; + std::vector screenTextureFramebuffers = {}; vk::UniqueDeviceMemory framebufferMemory = {}; std::map renderPassCache; @@ -89,9 +92,14 @@ class RendererVK final : public Renderer { vk::RenderPass getRenderPass(vk::Format colorFormat, std::optional depthFormat); vk::RenderPass getRenderPass(PICA::ColorFmt colorFormat, std::optional depthFormat); + std::unique_ptr descriptorUpdateBatch; + + // Display pipeline data std::unique_ptr displayDescriptorHeap; vk::UniquePipeline displayPipeline; vk::UniquePipelineLayout displayPipelineLayout; + std::vector topDisplayPipelineDescriptorSet; + std::vector bottomDisplayPipelineDescriptorSet; // Recreate the swapchain, possibly re-using the old one in the case of a resize vk::Result recreateSwapchain(vk::SurfaceKHR surface, vk::Extent2D swapchainExtent); diff --git a/src/core/renderer_vk/renderer_vk.cpp b/src/core/renderer_vk/renderer_vk.cpp index 49543bc5..0a0450bb 100644 --- a/src/core/renderer_vk/renderer_vk.cpp +++ b/src/core/renderer_vk/renderer_vk.cpp @@ -595,27 +595,53 @@ void RendererVK::display() { //// Render Frame(Simulated - just clear the images to different colors for now) { - static const std::array frameScopeColor = {{1.0f, 0.0f, 1.0f, 1.0f}}; + static const std::array renderScreenScopeColor = {{1.0f, 0.0f, 1.0f, 1.0f}}; - Vulkan::DebugLabelScope debugScope(getCurrentCommandBuffer(), frameScopeColor, "Frame"); - - // Prepare images for color-clear + Vulkan::DebugLabelScope debugScope(getCurrentCommandBuffer(), renderScreenScopeColor, "Render Screen"); + // Prepare screen texture for rendering into getCurrentCommandBuffer().pipelineBarrier( - vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {}, + vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::DependencyFlags(), {}, {}, { vk::ImageMemoryBarrier( - vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, - vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, screenTexture[frameBufferingIndex].get(), - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) + vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eColorAttachmentWrite, vk::ImageLayout::eUndefined, + vk::ImageLayout::eColorAttachmentOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + screenTexture[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) ), } ); - static const std::array topClearColor = {{1.0f, 0.0f, 0.0f, 1.0f}}; - static const std::array bottomClearColor = {{0.0f, 1.0f, 0.0f, 1.0f}}; - getCurrentCommandBuffer().clearColorImage( - screenTexture[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, topClearColor, - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) - ); + + vk::RenderPassBeginInfo renderPassBeginInfo = {}; + renderPassBeginInfo.renderPass = getRenderPass(vk::Format::eR8G8B8A8Unorm, {}); + + renderPassBeginInfo.framebuffer = screenTextureFramebuffers[frameBufferingIndex].get(); + renderPassBeginInfo.renderArea.offset = vk::Offset2D(); + renderPassBeginInfo.renderArea.extent = vk::Extent2D(400, 240 * 2); + + getCurrentCommandBuffer().beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline); + + // Render top screen + if (topActiveFb) { + getCurrentCommandBuffer().bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, displayPipelineLayout.get(), 0, {topDisplayPipelineDescriptorSet[frameBufferingIndex]}, {} + ); + getCurrentCommandBuffer().bindPipeline(vk::PipelineBindPoint::eGraphics, displayPipeline.get()); + getCurrentCommandBuffer().setViewport(0, vk::Viewport(0, 0, 400, 240)); + getCurrentCommandBuffer().setScissor(0, vk::Rect2D({0, 0}, {400, 240})); + getCurrentCommandBuffer().draw(3, 1, 0, 0); + } + + // Render bottom screen + if (bottomActiveFb) { + getCurrentCommandBuffer().bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, displayPipelineLayout.get(), 0, {bottomDisplayPipelineDescriptorSet[frameBufferingIndex]}, {} + ); + getCurrentCommandBuffer().bindPipeline(vk::PipelineBindPoint::eGraphics, displayPipeline.get()); + getCurrentCommandBuffer().setViewport(0, vk::Viewport(40, 0, 320, 240)); + getCurrentCommandBuffer().setScissor(0, vk::Rect2D({40, 0}, {320, 240})); + getCurrentCommandBuffer().draw(3, 1, 0, 0); + } + + getCurrentCommandBuffer().endRenderPass(); } //// Present @@ -1049,8 +1075,10 @@ void RendererVK::initGraphicsContext(SDL_Window* window) { screenTextureInfo.setInitialLayout(vk::ImageLayout::eUndefined); screenTexture.resize(frameBufferingCount); + screenTextureViews.resize(frameBufferingCount); + screenTextureFramebuffers.resize(frameBufferingCount); - for (usize i = 0; i < frameBufferingCount; i++) { + for (usize i = 0; i < frameBufferingCount; ++i) { if (auto createResult = device->createSemaphoreUnique(semaphoreInfo); createResult.result == vk::Result::eSuccess) { swapImageFreeSemaphore[i] = std::move(createResult.value); @@ -1093,17 +1121,68 @@ void RendererVK::initGraphicsContext(SDL_Window* window) { } } + // Memory is bounded, create views and framebuffer for screentexture + vk::ImageViewCreateInfo screenTextureViewCreateInfo = {}; + screenTextureViewCreateInfo.viewType = vk::ImageViewType::e2D; + screenTextureViewCreateInfo.format = vk::Format::eR8G8B8A8Unorm; + screenTextureViewCreateInfo.components.r = vk::ComponentSwizzle::eR; + screenTextureViewCreateInfo.components.g = vk::ComponentSwizzle::eG; + screenTextureViewCreateInfo.components.b = vk::ComponentSwizzle::eB; + screenTextureViewCreateInfo.components.a = vk::ComponentSwizzle::eA; + screenTextureViewCreateInfo.subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; + + for (usize i = 0; i < frameBufferingCount; ++i) { + screenTextureViewCreateInfo.image = screenTexture[i].get(); + + if (auto createResult = device->createImageViewUnique(screenTextureViewCreateInfo); createResult.result == vk::Result::eSuccess) { + screenTextureViews[i] = std::move(createResult.value); + } else { + Helpers::panic("Error creating screen texture view: %s\n", vk::to_string(createResult.result).c_str()); + } + + vk::FramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.setRenderPass(getRenderPass(vk::Format::eR8G8B8A8Unorm, {})); + framebufferInfo.setAttachments(screenTextureViews[i].get()); + framebufferInfo.setWidth(400); + framebufferInfo.setHeight(240 * 2); + framebufferInfo.setLayers(1); + if (auto createResult = device->createFramebufferUnique(framebufferInfo); createResult.result == vk::Result::eSuccess) { + screenTextureFramebuffers[i] = std::move(createResult.value); + } else { + Helpers::panic("Error creating screen-texture framebuffer: %s\n", vk::to_string(createResult.result).c_str()); + } + } + static vk::DescriptorSetLayoutBinding displayShaderLayout[] = { {// Just a singular texture slot 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, }; + if (auto createResult = Vulkan::DescriptorUpdateBatch::create(device.get()); createResult.has_value()) { + descriptorUpdateBatch = std::make_unique(std::move(createResult.value())); + } else { + Helpers::panic("Error creating descriptor update batch\n"); + } + if (auto createResult = Vulkan::DescriptorHeap::create(device.get(), displayShaderLayout); createResult.has_value()) { displayDescriptorHeap = std::make_unique(std::move(createResult.value())); } else { Helpers::panic("Error creating descriptor heap\n"); } + for (usize i = 0; i < frameBufferingCount; ++i) { + if (auto allocateResult = displayDescriptorHeap->allocateDescriptorSet(); allocateResult.has_value()) { + topDisplayPipelineDescriptorSet.emplace_back(allocateResult.value()); + } else { + Helpers::panic("Error creating descriptor set\n"); + } + if (auto allocateResult = displayDescriptorHeap->allocateDescriptorSet(); allocateResult.has_value()) { + bottomDisplayPipelineDescriptorSet.emplace_back(allocateResult.value()); + } else { + Helpers::panic("Error creating descriptor set\n"); + } + } + auto vk_resources = cmrc::RendererVK::get_filesystem(); auto displayVertexShader = vk_resources.open("vulkan_display.vert.spv"); auto displayFragmentShader = vk_resources.open("vulkan_display.frag.spv");