From 6dcd09af3e33d612543f0ff38af072f1db34d1a5 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Thu, 27 Jul 2023 22:16:02 -0700 Subject: [PATCH] Implement basic color/depth render-texture cache --- include/renderer_vk/renderer_vk.hpp | 12 ++ src/core/renderer_vk/renderer_vk.cpp | 159 ++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/include/renderer_vk/renderer_vk.hpp b/include/renderer_vk/renderer_vk.hpp index 700861b2..fa349148 100644 --- a/include/renderer_vk/renderer_vk.hpp +++ b/include/renderer_vk/renderer_vk.hpp @@ -48,6 +48,18 @@ class RendererVK final : public Renderer { std::vector swapImageFreeSemaphore = {}; std::vector renderFinishedSemaphore = {}; std::vector frameFinishedFences = {}; + struct Texture { + vk::UniqueImage image; + vk::UniqueDeviceMemory imageMemory; + vk::UniqueImageView imageView; + }; + std::map textureCache; + + static u32 colorBufferHash(u32 loc, u32 size, PICA::ColorFmt format); + static u32 depthBufferHash(u32 loc, u32 size, PICA::DepthFmt format); + + Texture& getColorRenderTexture(); + Texture& getDepthRenderTexture(); std::vector topScreenImages = {}; std::vector bottomScreenImages = {}; diff --git a/src/core/renderer_vk/renderer_vk.cpp b/src/core/renderer_vk/renderer_vk.cpp index 61f3186a..f255eb0b 100644 --- a/src/core/renderer_vk/renderer_vk.cpp +++ b/src/core/renderer_vk/renderer_vk.cpp @@ -25,6 +25,124 @@ static s32 findQueueFamily( return -1; } +u32 RendererVK::colorBufferHash(u32 loc, u32 size, PICA::ColorFmt format) { + return std::rotl(loc, 17) ^ std::rotr(size, 23) ^ (static_cast(format) << 60); +} +u32 RendererVK::depthBufferHash(u32 loc, u32 size, PICA::DepthFmt format) { + return std::rotl(loc, 17) ^ std::rotr(size, 29) ^ (static_cast(format) << 60); +} + +RendererVK::Texture& RendererVK::getColorRenderTexture() { + const u32 renderTextureHash = + colorBufferHash(colourBufferLoc, fbSize[0] * fbSize[1] * PICA::sizePerPixel(colourBufferFormat), colourBufferFormat); + + // Cache hit + if (textureCache.contains(renderTextureHash)) { + return textureCache.at(renderTextureHash); + } + + // Cache miss + Texture& newTexture = textureCache[renderTextureHash]; + + vk::ImageCreateInfo textureInfo = {}; + textureInfo.setImageType(vk::ImageType::e2D); + textureInfo.setFormat(Vulkan::colorFormatToVulkan(colourBufferFormat)); + textureInfo.setExtent(vk::Extent3D(fbSize[0], fbSize[1], 1)); + textureInfo.setMipLevels(1); + textureInfo.setArrayLayers(1); + textureInfo.setSamples(vk::SampleCountFlagBits::e1); + textureInfo.setTiling(vk::ImageTiling::eOptimal); + textureInfo.setUsage( + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eTransferSrc | + vk::ImageUsageFlagBits::eTransferDst + ); + textureInfo.setSharingMode(vk::SharingMode::eExclusive); + textureInfo.setInitialLayout(vk::ImageLayout::eUndefined); + + if (auto createResult = device->createImageUnique(textureInfo); createResult.result == vk::Result::eSuccess) { + newTexture.image = std::move(createResult.value); + } else { + Helpers::panic("Error creating color render-texture image: %s\n", vk::to_string(createResult.result).c_str()); + } + + vk::ImageViewCreateInfo viewInfo = {}; + viewInfo.image = newTexture.image.get(); + viewInfo.viewType = vk::ImageViewType::e2D; + viewInfo.format = Vulkan::colorFormatToVulkan(colourBufferFormat); + viewInfo.components = vk::ComponentMapping(); + viewInfo.subresourceRange = vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1); + + if (auto [result, imageMemory] = Vulkan::commitImageHeap(device.get(), physicalDevice, {&newTexture.image.get(), 1}); + result == vk::Result::eSuccess) { + newTexture.imageMemory = std::move(imageMemory); + } else { + Helpers::panic("Error allocating color render-texture memory: %s\n", vk::to_string(result).c_str()); + } + + if (auto createResult = device->createImageViewUnique(viewInfo); createResult.result == vk::Result::eSuccess) { + newTexture.imageView = std::move(createResult.value); + } else { + Helpers::panic("Error creating color render-texture: %s\n", vk::to_string(createResult.result).c_str()); + } + + return newTexture; +} + +RendererVK::Texture& RendererVK::getDepthRenderTexture() { + const u32 renderTextureHash = depthBufferHash(depthBufferLoc, fbSize[0] * fbSize[1] * PICA::sizePerPixel(depthBufferFormat), depthBufferFormat); + + // Cache hit + if (textureCache.contains(renderTextureHash)) { + return textureCache.at(renderTextureHash); + } + + // Cache miss + Texture& newTexture = textureCache[renderTextureHash]; + + vk::ImageCreateInfo textureInfo = {}; + textureInfo.setImageType(vk::ImageType::e2D); + textureInfo.setFormat(Vulkan::depthFormatToVulkan(depthBufferFormat)); + textureInfo.setExtent(vk::Extent3D(fbSize[0], fbSize[1], 1)); + textureInfo.setMipLevels(1); + textureInfo.setArrayLayers(1); + textureInfo.setSamples(vk::SampleCountFlagBits::e1); + textureInfo.setTiling(vk::ImageTiling::eOptimal); + textureInfo.setUsage( + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eTransferSrc | + vk::ImageUsageFlagBits::eTransferDst + ); + textureInfo.setSharingMode(vk::SharingMode::eExclusive); + textureInfo.setInitialLayout(vk::ImageLayout::eUndefined); + + if (auto createResult = device->createImageUnique(textureInfo); createResult.result == vk::Result::eSuccess) { + newTexture.image = std::move(createResult.value); + } else { + Helpers::panic("Error creating depth render-texture image: %s\n", vk::to_string(createResult.result).c_str()); + } + + vk::ImageViewCreateInfo viewInfo = {}; + viewInfo.image = newTexture.image.get(); + viewInfo.viewType = vk::ImageViewType::e2D; + viewInfo.format = Vulkan::depthFormatToVulkan(depthBufferFormat); + viewInfo.components = vk::ComponentMapping(); + viewInfo.subresourceRange = vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1); + + if (auto createResult = device->createImageViewUnique(viewInfo); createResult.result == vk::Result::eSuccess) { + newTexture.imageView = std::move(createResult.value); + } else { + Helpers::panic("Error creating depth render-texture: %s\n", vk::to_string(createResult.result).c_str()); + } + + if (auto [result, imageMemory] = Vulkan::commitImageHeap(device.get(), physicalDevice, {&newTexture.image.get(), 1}); + result == vk::Result::eSuccess) { + newTexture.imageMemory = std::move(imageMemory); + } else { + Helpers::panic("Error allocating depth render-texture memory: %s\n", vk::to_string(result).c_str()); + } + + return newTexture; +} + vk::RenderPass RendererVK::getRenderPass(PICA::ColorFmt colorFormat, std::optional depthFormat) { u32 renderPassHash = static_cast(colorFormat); @@ -739,7 +857,7 @@ void RendererVK::initGraphicsContext(SDL_Window* window) { if (auto createResult = device->createFenceUnique(fenceInfo); createResult.result == vk::Result::eSuccess) { frameFinishedFences[i] = std::move(createResult.value); } else { - Helpers::panic("Error creating 'present-ready' semaphore: %s\n", vk::to_string(createResult.result).c_str()); + Helpers::panic("Error creating 'frame-finished' fence: %s\n", vk::to_string(createResult.result).c_str()); } if (auto createResult = device->createImageUnique(topScreenInfo); createResult.result == vk::Result::eSuccess) { @@ -786,6 +904,45 @@ void RendererVK::drawVertices(PICA::PrimType primType, std::span(depthControl)); const vk::RenderPass curRenderPass = getRenderPass(colourBufferFormat, depthTestEnable ? std::make_optional(depthBufferFormat) : std::nullopt); + + // Create framebuffer, find a way to cache this! + vk::Framebuffer curFramebuffer = {}; + { + std::vector renderTargets; + + const auto& colorTexture = getColorRenderTexture(); + renderTargets.emplace_back(colorTexture.imageView.get()); + + if (depthTestEnable) { + const auto& depthTexture = getDepthRenderTexture(); + renderTargets.emplace_back(depthTexture.imageView.get()); + } + + vk::FramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.setRenderPass(curRenderPass); + framebufferInfo.setAttachments(renderTargets); + framebufferInfo.setWidth(fbSize[0]); + framebufferInfo.setHeight(fbSize[1]); + framebufferInfo.setLayers(1); + if (auto createResult = device->createFramebufferUnique(framebufferInfo); createResult.result == vk::Result::eSuccess) { + curFramebuffer = (frameFramebuffers[frameBufferingIndex].emplace_back(std::move(createResult.value))).get(); + } else { + Helpers::panic("Error creating render-texture framebuffer: %s\n", vk::to_string(createResult.result).c_str()); + } + } + + vk::RenderPassBeginInfo renderBeginInfo = {}; + renderBeginInfo.renderPass = curRenderPass; + static const vk::ClearValue ClearColors[] = { + vk::ClearColorValue(std::array{0.0f, 0.0f, 0.0f, 0.0f}), + vk::ClearDepthStencilValue(1.0f, 0), + vk::ClearColorValue(std::array{0.0f, 0.0f, 0.0f, 0.0f}), + }; + renderBeginInfo.pClearValues = ClearColors; + renderBeginInfo.clearValueCount = std::size(ClearColors); + renderBeginInfo.renderArea.extent.width = fbSize[0]; + renderBeginInfo.renderArea.extent.height = fbSize[1]; + renderBeginInfo.framebuffer = curFramebuffer; } void RendererVK::screenshot(const std::string& name) {}