/* * 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 { namespace { constexpr uint32_t SAMPLE_SIZE_WIDTH = 5; constexpr uint32_t SAMPLE_SIZE_HEIGHT = 5; constexpr uint32_t SAMPLE_SIZE = SAMPLE_SIZE_WIDTH * SAMPLE_SIZE_HEIGHT; constexpr uint32_t SAMPLE_CENTER = SAMPLE_SIZE / 2; } void DepthBufferQuery::Init() { auto device = renderer.GetContext().device->device; vk::BufferCreateInfo bufferInfo = { {}, SAMPLE_SIZE * 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[SAMPLE_CENTER] > 0 && cpuDepthBuffer[SAMPLE_CENTER] < 1) return cpuDepthBuffer[SAMPLE_CENTER]; std::sort(cpuDepthBuffer, cpuDepthBuffer + SAMPLE_SIZE); uint32_t start = UINT32_MAX, end = UINT32_MAX; for (uint32_t i = 0; i < SAMPLE_SIZE; i++) { float f = cpuDepthBuffer[i]; if (f > 0 && start == UINT32_MAX) start = i; if (f < 1 && end == UINT32_MAX) end = i; else if (f >= 1) break; } if (start == UINT32_MAX || end == UINT32_MAX) return cpuDepthBuffer[SAMPLE_CENTER]; return cpuDepthBuffer[(start + end) / 2]; } 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 - SAMPLE_SIZE_WIDTH, std::max(0, x)); int32_t y = static_cast(depthQueryCoordinates.y * depthExtent.height); y = std::min(depthExtent.height - SAMPLE_SIZE_HEIGHT, std::max(0, y)); return { x, y, 0 }; } void DepthBufferQuery::Encode(vk::CommandBuffer& commandBuffer) { if (!copyDepthBuffer) return; copyDepthBuffer = false; std::fill(cpuDepthBuffer, cpuDepthBuffer + SAMPLE_SIZE, -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 = { SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT, 1 }; const vk::ImageSubresourceLayers layout = { vk::ImageAspectFlagBits::eDepth, 0, 0, 1 }; vk::BufferImageCopy imgCopy = { 0, 0, 0, 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); } }