Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Source/Renderer/Renderer/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ namespace Renderer
virtual void CopyBuffer(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range) = 0;
// Immediately copies using an immediate command list
virtual void CopyBufferImmediate(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range) = 0;
// Debug/automation readback. These calls wait for the graphics queue and
// should not be used in performance-sensitive runtime paths.
virtual bool ReadImageImmediate(ImageID image, void* destination, size_t destinationSize) = 0;
virtual bool ReadImageImmediate(DepthImageID image, void* destination, size_t destinationSize) = 0;
void UploadToBuffer(BufferID dstBuffer, u64 dstOffset, void* srcData, u64 srcOffset, u64 srcSize);

virtual void* MapBuffer(BufferID buffer) = 0;
Expand Down
134 changes: 134 additions & 0 deletions Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <tracy/TracyVulkan.hpp>
#include <imgui/backends/imgui_impl_vulkan.h>

#include <cstring>

namespace Renderer
{
RendererVK::RendererVK(Novus::Window* window)
Expand Down Expand Up @@ -2071,6 +2073,138 @@ namespace Renderer
_device->EndSingleTimeCommands(commandList);
}

bool RendererVK::ReadImageImmediate(ImageID imageID, void* destination, size_t destinationSize)
{
if (imageID == ImageID::Invalid() || destination == nullptr || destinationSize == 0)
return false;

const uvec2 dimensions = _imageHandler->GetDimensions(imageID, 0);
if (dimensions.x == 0 || dimensions.y == 0)
return false;

BufferDesc readbackDesc;
readbackDesc.name = "Immediate color image readback";
readbackDesc.usage = BufferUsage::TRANSFER_DESTINATION;
readbackDesc.cpuAccess = BufferCPUAccess::ReadOnly;
readbackDesc.size = destinationSize;
const BufferID readbackBuffer = _bufferHandler->CreateBuffer(readbackDesc);
if (readbackBuffer == BufferID::Invalid())
return false;

VkImage image = _imageHandler->GetImage(imageID);
VkBuffer buffer = _bufferHandler->GetBuffer(readbackBuffer);
VkCommandBuffer commandBuffer = _device->BeginSingleTimeCommands();

_device->TransitionImageLayout(
commandBuffer,
image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1,
1);

VkBufferImageCopy copyRegion = {};
copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.imageSubresource.layerCount = 1;
copyRegion.imageExtent = { dimensions.x, dimensions.y, 1 };
vkCmdCopyImageToBuffer(
commandBuffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
buffer,
1,
&copyRegion);

_device->TransitionImageLayout(
commandBuffer,
image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
1,
1);
_device->EndSingleTimeCommands(commandBuffer);

void* mappedMemory = MapBuffer(readbackBuffer);
if (mappedMemory == nullptr)
{
_bufferHandler->DestroyBuffer(readbackBuffer);
return false;
}

std::memcpy(destination, mappedMemory, destinationSize);
UnmapBuffer(readbackBuffer);
_bufferHandler->DestroyBuffer(readbackBuffer);
return true;
}

bool RendererVK::ReadImageImmediate(DepthImageID imageID, void* destination, size_t destinationSize)
{
if (imageID == DepthImageID::Invalid() || destination == nullptr || destinationSize == 0)
return false;

const uvec2 dimensions = _imageHandler->GetDimensions(imageID);
if (dimensions.x == 0 || dimensions.y == 0)
return false;

BufferDesc readbackDesc;
readbackDesc.name = "Immediate depth image readback";
readbackDesc.usage = BufferUsage::TRANSFER_DESTINATION;
readbackDesc.cpuAccess = BufferCPUAccess::ReadOnly;
readbackDesc.size = destinationSize;
const BufferID readbackBuffer = _bufferHandler->CreateBuffer(readbackDesc);
if (readbackBuffer == BufferID::Invalid())
return false;

VkImage image = _imageHandler->GetImage(imageID);
VkBuffer buffer = _bufferHandler->GetBuffer(readbackBuffer);
VkCommandBuffer commandBuffer = _device->BeginSingleTimeCommands();

_device->TransitionImageLayout(
commandBuffer,
image,
VK_IMAGE_ASPECT_DEPTH_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1,
1);

VkBufferImageCopy copyRegion = {};
copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
copyRegion.imageSubresource.layerCount = 1;
copyRegion.imageExtent = { dimensions.x, dimensions.y, 1 };
vkCmdCopyImageToBuffer(
commandBuffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
buffer,
1,
&copyRegion);

_device->TransitionImageLayout(
commandBuffer,
image,
VK_IMAGE_ASPECT_DEPTH_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
1,
1);
_device->EndSingleTimeCommands(commandBuffer);

void* mappedMemory = MapBuffer(readbackBuffer);
if (mappedMemory == nullptr)
{
_bufferHandler->DestroyBuffer(readbackBuffer);
return false;
}

std::memcpy(destination, mappedMemory, destinationSize);
UnmapBuffer(readbackBuffer);
_bufferHandler->DestroyBuffer(readbackBuffer);
return true;
}

void RendererVK::FillBuffer(CommandListID commandListID, BufferID dstBuffer, u64 dstOffset, u64 size, u32 data)
{
VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer(commandListID);
Expand Down
2 changes: 2 additions & 0 deletions Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ namespace Renderer
void CopyBuffer(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range) override;
// Immediately copies using an immediate command list
void CopyBufferImmediate(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range) override;
bool ReadImageImmediate(ImageID image, void* destination, size_t destinationSize) override;
bool ReadImageImmediate(DepthImageID image, void* destination, size_t destinationSize) override;

[[nodiscard]] void* MapBuffer(BufferID buffer) override;
void UnmapBuffer(BufferID buffer) override;
Expand Down
Loading