From e54404ec61dd8100fac3fbf30f45b948a768b5a5 Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Thu, 1 Aug 2024 10:29:07 +0200 Subject: [PATCH] Add code to allow for depth buffer query (Fixes #18) --- openVulkanoCpp/Base/Render/IRenderer.hpp | 3 + openVulkanoCpp/Vulkan/DepthBufferQuery.cpp | 96 ++++++++++++++++++++++ openVulkanoCpp/Vulkan/DepthBufferQuery.hpp | 48 +++++++++++ openVulkanoCpp/Vulkan/FrameBuffer.hpp | 2 + openVulkanoCpp/Vulkan/RenderPass.cpp | 4 +- openVulkanoCpp/Vulkan/Renderer.cpp | 9 ++ openVulkanoCpp/Vulkan/Renderer.hpp | 8 +- openVulkanoCpp/Vulkan/SwapChain.hpp | 17 +--- 8 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 openVulkanoCpp/Vulkan/DepthBufferQuery.cpp create mode 100644 openVulkanoCpp/Vulkan/DepthBufferQuery.hpp diff --git a/openVulkanoCpp/Base/Render/IRenderer.hpp b/openVulkanoCpp/Base/Render/IRenderer.hpp index 3c01ef3..59d8dd7 100644 --- a/openVulkanoCpp/Base/Render/IRenderer.hpp +++ b/openVulkanoCpp/Base/Render/IRenderer.hpp @@ -35,5 +35,8 @@ namespace OpenVulkano virtual Scene::UI::Ui* GetActiveUi() = 0; virtual IResourceManager* GetIResourceManager() = 0; + + virtual float GetLastQueriedDepthValue() = 0; + virtual void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) = 0; }; } diff --git a/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp b/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp new file mode 100644 index 0000000..98e200e --- /dev/null +++ b/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp @@ -0,0 +1,96 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "DepthBufferQuery.hpp" +#include "Renderer.hpp" +#include + +//TODO resize + +namespace OpenVulkano::Vulkan +{ + void DepthBufferQuery::Init() + { + auto device = renderer.GetContext().device->device; + + vk::BufferCreateInfo bufferInfo = { {}, 25 * sizeof(float), vk::BufferUsageFlagBits::eTransferDst }; + bufferDepth = device.createBuffer(bufferInfo); + const vk::MemoryRequirements memRequirements = device.getBufferMemoryRequirements(bufferDepth); + size_t size = memRequirements.size; + const vk::MemoryAllocateInfo memAllocInfo = { size, renderer.GetContext().device->GetMemoryType(memRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible) }; + + memory = device.allocateMemory(memAllocInfo); + cpuDepthBuffer = static_cast(device.mapMemory(memory, 0, VK_WHOLE_SIZE, {})); + + device.bindBufferMemory(bufferDepth, memory, 0); + } + + void DepthBufferQuery::Close() + { + auto device = renderer.GetContext().device->device; + device.destroy(bufferDepth); + device.unmapMemory(memory); + device.free(memory); + cpuDepthBuffer = nullptr; + } + + void DepthBufferQuery::Resize(uint32_t width, uint32_t height) + { + //TODO + } + + float DepthBufferQuery::GetQueriedValue() const + { + if (cpuDepthBuffer[0] == -2) return -2; + if (cpuDepthBuffer[12] > 0 && cpuDepthBuffer[12] < 1) return cpuDepthBuffer[12]; + double val = 0; + int validCount = 0; + for (int i = 0; i < 25; i++) + { + float f = cpuDepthBuffer[i]; + if (f > 0 && f < 1) + { + val += f; + validCount++; + } + } + if (validCount == 0) return 1; // Prevent divide by 0 + return val / validCount; + } + + vk::Offset3D DepthBufferQuery::GetCopyOffset() const + { + vk::Extent3D depthExtent = renderer.GetContext().swapChain.GetCurrentDepthBuffer().extent; + + int32_t x = static_cast(depthQueryCoordinates.x * depthExtent.width); + x = std::min(depthExtent.width - 5, std::max(0, x)); + + int32_t y = static_cast(depthQueryCoordinates.y * depthExtent.height); + y = std::min(depthExtent.height - 5, std::max(0, y)); + + return { x, y, 0 }; + } + + void DepthBufferQuery::Encode(vk::CommandBuffer& commandBuffer) + { + if (!copyDepthBuffer) return; + copyDepthBuffer = false; + std::fill(cpuDepthBuffer, cpuDepthBuffer + 25, -2.0f); // Invalidate data in buffer to allow detecting if copy is done + const vk::ImageAspectFlags aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; + const Image& depthBufferImage = renderer.GetContext().swapChain.GetCurrentDepthBuffer(); + + constexpr vk::Extent3D copySize = { 5, 5, 1 }; + const vk::ImageSubresourceLayers layout = { vk::ImageAspectFlagBits::eDepth, 0, 0, 1 }; + vk::BufferImageCopy imgCopy = { 0, 5, 5, layout, GetCopyOffset(), copySize }; + + const vk::ImageMemoryBarrier imgMemBarrier({}, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal, 0, 0, depthBufferImage.image, vk::ImageSubresourceRange(aspectMask, 0, 1, 0, 1)); + commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, imgMemBarrier); + + commandBuffer.copyImageToBuffer(depthBufferImage.image, vk::ImageLayout::eTransferSrcOptimal, bufferDepth, 1, &imgCopy); + + depthBufferImage.SetLayout(commandBuffer, aspectMask, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal); + } +} diff --git a/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp b/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp new file mode 100644 index 0000000..167912d --- /dev/null +++ b/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp @@ -0,0 +1,48 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math/Math.hpp" +#include "Vulkan/Image.hpp" + +namespace OpenVulkano::Vulkan +{ + class Renderer; + + class DepthBufferQuery final + { + Renderer& renderer; + vk::DeviceMemory memory; + vk::Buffer bufferDepth; + float* cpuDepthBuffer = nullptr; + Math::Vector2f depthQueryCoordinates = { 0.5f, 0.5f }; + bool copyDepthBuffer = true; + + vk::Offset3D GetCopyOffset() const; + + public: + DepthBufferQuery(Renderer& renderer): renderer(renderer) {} + + ~DepthBufferQuery() { if (cpuDepthBuffer != nullptr) Close(); } + + void Init(); + + void Close(); + + void Encode(vk::CommandBuffer& commandBuffer); + + void Resize(uint32_t width, uint32_t height); + + float GetQueriedValue() const; + + void SetQueryCoordinates(const Math::Vector2f& coords) + { + copyDepthBuffer = true; + depthQueryCoordinates = coords; + } + }; +} diff --git a/openVulkanoCpp/Vulkan/FrameBuffer.hpp b/openVulkanoCpp/Vulkan/FrameBuffer.hpp index fcf54eb..e9d68ca 100644 --- a/openVulkanoCpp/Vulkan/FrameBuffer.hpp +++ b/openVulkanoCpp/Vulkan/FrameBuffer.hpp @@ -90,5 +90,7 @@ namespace OpenVulkano::Vulkan [[nodiscard]] const vk::Viewport& GetFullscreenViewport() const { return fullscreenViewport; } [[nodiscard]] const vk::Rect2D& GetFullscreenScissor() const { return fullscreenScissor; } + + [[nodiscard]] const Image& GetCurrentDepthBuffer() { return depthBuffer; } }; } diff --git a/openVulkanoCpp/Vulkan/RenderPass.cpp b/openVulkanoCpp/Vulkan/RenderPass.cpp index b7afa50..979ed5f 100644 --- a/openVulkanoCpp/Vulkan/RenderPass.cpp +++ b/openVulkanoCpp/Vulkan/RenderPass.cpp @@ -57,7 +57,7 @@ namespace OpenVulkano::Vulkan if (m_frameBuffer->UseDepthBuffer()) { // Depth attachment attachments.emplace_back(vk::AttachmentDescriptionFlags(), m_frameBuffer->GetDepthFormat(), vk::SampleCountFlagBits::e1, - m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eDontCare, m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, + m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eDepthStencilAttachmentOptimal); depthReference = new vk::AttachmentReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); } @@ -87,4 +87,4 @@ namespace OpenVulkano::Vulkan { renderPass = m_device.createRenderPass(renderPassCreateInfo); } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/Vulkan/Renderer.cpp b/openVulkanoCpp/Vulkan/Renderer.cpp index 18e94a8..9931420 100644 --- a/openVulkanoCpp/Vulkan/Renderer.cpp +++ b/openVulkanoCpp/Vulkan/Renderer.cpp @@ -18,6 +18,11 @@ namespace OpenVulkano::Vulkan { + Renderer::Renderer() + : depthBufferQuery(*this) + { + } + void Renderer::Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) { logger = Logger::RENDER; @@ -62,6 +67,8 @@ namespace OpenVulkano::Vulkan } } + depthBufferQuery.Init(); + logger->info("Vulkan renderer initialized"); } @@ -87,6 +94,7 @@ namespace OpenVulkano::Vulkan closeables.pop_back(); closeable->Close(); } + depthBufferQuery.Close(); uiRenderer.Close(); resourceManager.Close(); commands.clear(); @@ -138,6 +146,7 @@ namespace OpenVulkano::Vulkan CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); cmdHelper->cmdBuffer.executeCommands(submitBuffers[currentImageId].size(), submitBuffers[currentImageId].data()); context.swapChainRenderPass.End(cmdHelper->cmdBuffer); + depthBufferQuery.Encode(cmdHelper->cmdBuffer); uiRenderer.DrawUiFrame(cmdHelper->cmdBuffer); cmdHelper->cmdBuffer.end(); std::array stateFlags = { vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput), vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput) }; diff --git a/openVulkanoCpp/Vulkan/Renderer.hpp b/openVulkanoCpp/Vulkan/Renderer.hpp index 5740256..064e1c6 100644 --- a/openVulkanoCpp/Vulkan/Renderer.hpp +++ b/openVulkanoCpp/Vulkan/Renderer.hpp @@ -16,6 +16,7 @@ #include "CommandHelper.hpp" #include "Base/EngineConfiguration.hpp" #include "Resources/ResourceManager.hpp" +#include "DepthBufferQuery.hpp" #include #include @@ -40,9 +41,10 @@ namespace OpenVulkano::Vulkan std::vector> submitBuffers; UiRenderer uiRenderer; std::vector closeables; + DepthBufferQuery depthBufferQuery; public: - Renderer() = default; + Renderer(); ~Renderer() override = default; void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) override; @@ -86,5 +88,9 @@ namespace OpenVulkano::Vulkan void UnregisterCloseable(ICloseable* closeable) { Utils::Remove(closeables, closeable); } IResourceManager* GetIResourceManager() override { return &resourceManager; } + + + float GetLastQueriedDepthValue() override { return depthBufferQuery.GetQueriedValue(); } + void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) override { depthBufferQuery.SetQueryCoordinates(depthCoordinates); } }; } diff --git a/openVulkanoCpp/Vulkan/SwapChain.hpp b/openVulkanoCpp/Vulkan/SwapChain.hpp index 0841437..934b705 100644 --- a/openVulkanoCpp/Vulkan/SwapChain.hpp +++ b/openVulkanoCpp/Vulkan/SwapChain.hpp @@ -45,7 +45,7 @@ namespace OpenVulkano vk::PresentModeKHR presentMode; std::vector imageAvailableSemaphores; uint32_t currentSemaphoreId = 0; - vk::Extent2D size{0,0}; + vk::Extent2D size{ 0, 0 }; public: vk::SwapchainKHR swapChain; @@ -59,10 +59,7 @@ namespace OpenVulkano void Resize(uint32_t newWidth, uint32_t newHeight); - [[nodiscard]] vk::Extent2D GetSize() const - { - return size; - } + [[nodiscard]] vk::Extent2D GetSize() const { return size; } uint32_t AcquireNextImage(const vk::Fence& fence = vk::Fence()); @@ -81,10 +78,7 @@ namespace OpenVulkano } } - [[nodiscard]] uint32_t GetImageCount() const - { - return images.size(); - } + [[nodiscard]] uint32_t GetImageCount() const { return images.size(); } vk::Semaphore& GetCurrentSemaphore() { return imageAvailableSemaphores[currentSemaphoreId]; } @@ -96,10 +90,7 @@ namespace OpenVulkano void DestroySwapChain(); protected: - vk::Format FindColorFormat() override - { - return surfaceFormat.format; - } + [[nodiscard]] vk::Format FindColorFormat() override { return surfaceFormat.format; } virtual vk::PresentModeKHR ChosePresentMode();