mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-09 00:12:14 +02:00
Vulkan: Implement StagingTexture2D on top of StagingBuffer
Greatly simplifies things, and we weren't using the linear texture implementation anyway.
This commit is contained in:
parent
4bc0e14995
commit
e241ec6666
@ -1007,10 +1007,8 @@ bool FramebufferManager::CreateReadbackTextures()
|
|||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||||
|
|
||||||
// We can't copy to/from color<->depth formats, so using a linear texture is not an option here.
|
m_depth_readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, EFB_WIDTH,
|
||||||
// TODO: Investigate if vkCmdBlitImage can be used. The documentation isn't that clear.
|
EFB_HEIGHT, EFB_DEPTH_TEXTURE_FORMAT);
|
||||||
m_depth_readback_texture = StagingTexture2DBuffer::Create(STAGING_BUFFER_TYPE_READBACK, EFB_WIDTH,
|
|
||||||
EFB_HEIGHT, EFB_DEPTH_TEXTURE_FORMAT);
|
|
||||||
if (!m_depth_copy_texture || !m_depth_readback_texture)
|
if (!m_depth_copy_texture || !m_depth_readback_texture)
|
||||||
{
|
{
|
||||||
ERROR_LOG(VIDEO, "Failed to create EFB depth readback texture");
|
ERROR_LOG(VIDEO, "Failed to create EFB depth readback texture");
|
||||||
|
@ -80,6 +80,9 @@ void StagingBuffer::InvalidateGPUCache(VkCommandBuffer command_buffer,
|
|||||||
VkPipelineStageFlagBits dest_pipeline_stage,
|
VkPipelineStageFlagBits dest_pipeline_stage,
|
||||||
VkDeviceSize offset, VkDeviceSize size)
|
VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
|
if (m_coherent)
|
||||||
|
return;
|
||||||
|
|
||||||
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
Util::BufferMemoryBarrier(command_buffer, m_buffer, VK_ACCESS_HOST_WRITE_BIT, dest_access_flags,
|
Util::BufferMemoryBarrier(command_buffer, m_buffer, VK_ACCESS_HOST_WRITE_BIT, dest_access_flags,
|
||||||
offset, size, VK_PIPELINE_STAGE_HOST_BIT, dest_pipeline_stage);
|
offset, size, VK_PIPELINE_STAGE_HOST_BIT, dest_pipeline_stage);
|
||||||
@ -90,6 +93,9 @@ void StagingBuffer::PrepareForGPUWrite(VkCommandBuffer command_buffer,
|
|||||||
VkPipelineStageFlagBits dst_pipeline_stage,
|
VkPipelineStageFlagBits dst_pipeline_stage,
|
||||||
VkDeviceSize offset, VkDeviceSize size)
|
VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
|
if (m_coherent)
|
||||||
|
return;
|
||||||
|
|
||||||
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
Util::BufferMemoryBarrier(command_buffer, m_buffer, 0, dst_access_flags, offset, size,
|
Util::BufferMemoryBarrier(command_buffer, m_buffer, 0, dst_access_flags, offset, size,
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dst_pipeline_stage);
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dst_pipeline_stage);
|
||||||
@ -99,6 +105,9 @@ void StagingBuffer::FlushGPUCache(VkCommandBuffer command_buffer, VkAccessFlagBi
|
|||||||
VkPipelineStageFlagBits src_pipeline_stage, VkDeviceSize offset,
|
VkPipelineStageFlagBits src_pipeline_stage, VkDeviceSize offset,
|
||||||
VkDeviceSize size)
|
VkDeviceSize size)
|
||||||
{
|
{
|
||||||
|
if (m_coherent)
|
||||||
|
return;
|
||||||
|
|
||||||
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
_assert_((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
Util::BufferMemoryBarrier(command_buffer, m_buffer, src_access_flags, VK_ACCESS_HOST_READ_BIT,
|
Util::BufferMemoryBarrier(command_buffer, m_buffer, src_access_flags, VK_ACCESS_HOST_READ_BIT,
|
||||||
offset, size, src_pipeline_stage, VK_PIPELINE_STAGE_HOST_BIT);
|
offset, size, src_pipeline_stage, VK_PIPELINE_STAGE_HOST_BIT);
|
||||||
@ -136,8 +145,9 @@ void StagingBuffer::Write(VkDeviceSize offset, const void* data, size_t size,
|
|||||||
FlushCPUCache(offset, size);
|
FlushCPUCache(offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Vulkan::StagingBuffer>
|
bool StagingBuffer::AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size,
|
||||||
StagingBuffer::Create(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsageFlags usage)
|
VkBufferUsageFlags usage, VkBuffer* out_buffer,
|
||||||
|
VkDeviceMemory* out_memory, bool* out_coherent)
|
||||||
{
|
{
|
||||||
VkBufferCreateInfo buffer_create_info = {
|
VkBufferCreateInfo buffer_create_info = {
|
||||||
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
|
||||||
@ -149,24 +159,22 @@ StagingBuffer::Create(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsage
|
|||||||
0, // uint32_t queueFamilyIndexCount
|
0, // uint32_t queueFamilyIndexCount
|
||||||
nullptr // const uint32_t* pQueueFamilyIndices
|
nullptr // const uint32_t* pQueueFamilyIndices
|
||||||
};
|
};
|
||||||
VkBuffer buffer;
|
|
||||||
VkResult res =
|
VkResult res =
|
||||||
vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, &buffer);
|
vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, out_buffer);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements requirements;
|
VkMemoryRequirements requirements;
|
||||||
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), buffer, &requirements);
|
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), *out_buffer, &requirements);
|
||||||
|
|
||||||
bool is_coherent;
|
|
||||||
u32 type_index;
|
u32 type_index;
|
||||||
if (type == STAGING_BUFFER_TYPE_UPLOAD)
|
if (type == STAGING_BUFFER_TYPE_UPLOAD)
|
||||||
type_index = g_vulkan_context->GetUploadMemoryType(requirements.memoryTypeBits, &is_coherent);
|
type_index = g_vulkan_context->GetUploadMemoryType(requirements.memoryTypeBits, out_coherent);
|
||||||
else
|
else
|
||||||
type_index = g_vulkan_context->GetReadbackMemoryType(requirements.memoryTypeBits, &is_coherent);
|
type_index = g_vulkan_context->GetReadbackMemoryType(requirements.memoryTypeBits, out_coherent);
|
||||||
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
VkMemoryAllocateInfo memory_allocate_info = {
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
||||||
@ -174,25 +182,36 @@ StagingBuffer::Create(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsage
|
|||||||
requirements.size, // VkDeviceSize allocationSize
|
requirements.size, // VkDeviceSize allocationSize
|
||||||
type_index // uint32_t memoryTypeIndex
|
type_index // uint32_t memoryTypeIndex
|
||||||
};
|
};
|
||||||
VkDeviceMemory memory;
|
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, out_memory);
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory);
|
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
vkDestroyBuffer(g_vulkan_context->GetDevice(), *out_buffer, nullptr);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), buffer, memory, 0);
|
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), *out_buffer, *out_memory, 0);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
vkDestroyBuffer(g_vulkan_context->GetDevice(), *out_buffer, nullptr);
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
vkFreeMemory(g_vulkan_context->GetDevice(), *out_memory, nullptr);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<Vulkan::StagingBuffer>(type, buffer, memory, size, is_coherent);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<StagingBuffer> StagingBuffer::Create(STAGING_BUFFER_TYPE type, VkDeviceSize size,
|
||||||
|
VkBufferUsageFlags usage)
|
||||||
|
{
|
||||||
|
VkBuffer buffer;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
bool coherent;
|
||||||
|
if (!AllocateBuffer(type, size, usage, &buffer, &memory, &coherent))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return std::make_unique<StagingBuffer>(type, buffer, memory, size, coherent);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -16,7 +16,7 @@ class StagingBuffer
|
|||||||
public:
|
public:
|
||||||
StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize size,
|
StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize size,
|
||||||
bool coherent);
|
bool coherent);
|
||||||
~StagingBuffer();
|
virtual ~StagingBuffer();
|
||||||
|
|
||||||
STAGING_BUFFER_TYPE GetType() const { return m_type; }
|
STAGING_BUFFER_TYPE GetType() const { return m_type; }
|
||||||
VkDeviceSize GetSize() const { return m_size; }
|
VkDeviceSize GetSize() const { return m_size; }
|
||||||
@ -33,6 +33,7 @@ public:
|
|||||||
void FlushCPUCache(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE);
|
void FlushCPUCache(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE);
|
||||||
|
|
||||||
// Upload part 2: Prepare for device read from the GPU side
|
// Upload part 2: Prepare for device read from the GPU side
|
||||||
|
// Implicit when submitting the command buffer, so rarely needed.
|
||||||
void InvalidateGPUCache(VkCommandBuffer command_buffer, VkAccessFlagBits dst_access_flags,
|
void InvalidateGPUCache(VkCommandBuffer command_buffer, VkAccessFlagBits dst_access_flags,
|
||||||
VkPipelineStageFlagBits dst_pipeline_stage, VkDeviceSize offset = 0,
|
VkPipelineStageFlagBits dst_pipeline_stage, VkDeviceSize offset = 0,
|
||||||
VkDeviceSize size = VK_WHOLE_SIZE);
|
VkDeviceSize size = VK_WHOLE_SIZE);
|
||||||
@ -59,6 +60,10 @@ public:
|
|||||||
VkBufferUsageFlags usage);
|
VkBufferUsageFlags usage);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Allocates the resources needed to create a staging buffer.
|
||||||
|
static bool AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VkBuffer* out_buffer, VkDeviceMemory* out_memory, bool* out_coherent);
|
||||||
|
|
||||||
STAGING_BUFFER_TYPE m_type;
|
STAGING_BUFFER_TYPE m_type;
|
||||||
VkBuffer m_buffer;
|
VkBuffer m_buffer;
|
||||||
VkDeviceMemory m_memory;
|
VkDeviceMemory m_memory;
|
||||||
|
@ -14,16 +14,16 @@
|
|||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
StagingTexture2D::StagingTexture2D(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format,
|
StagingTexture2D::StagingTexture2D(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory,
|
||||||
u32 stride)
|
VkDeviceSize size, bool coherent, u32 width, u32 height,
|
||||||
: m_type(type), m_width(width), m_height(height), m_format(format),
|
VkFormat format, u32 stride)
|
||||||
m_texel_size(Util::GetTexelSize(format)), m_row_stride(stride)
|
: StagingBuffer(type, buffer, memory, size, coherent), m_width(width), m_height(height),
|
||||||
|
m_format(format), m_texel_size(Util::GetTexelSize(format)), m_row_stride(stride)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
StagingTexture2D::~StagingTexture2D()
|
StagingTexture2D::~StagingTexture2D()
|
||||||
{
|
{
|
||||||
_assert_(!m_map_pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingTexture2D::ReadTexel(u32 x, u32 y, void* data, size_t data_size) const
|
void StagingTexture2D::ReadTexel(u32 x, u32 y, void* data, size_t data_size) const
|
||||||
@ -96,283 +96,13 @@ void StagingTexture2D::WriteTexels(u32 x, u32 y, u32 width, u32 height, const vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<StagingTexture2D> StagingTexture2D::Create(STAGING_BUFFER_TYPE type, u32 width,
|
void StagingTexture2D::CopyFromImage(VkCommandBuffer command_buffer, VkImage image,
|
||||||
u32 height, VkFormat format)
|
VkImageAspectFlags src_aspect, u32 x, u32 y, u32 width,
|
||||||
{
|
u32 height, u32 level, u32 layer)
|
||||||
// TODO: Using a buffer here as opposed to a linear texture is faster on AMD.
|
|
||||||
// NVIDIA also seems faster with buffers over textures.
|
|
||||||
#if 0
|
|
||||||
// Check for support for this format as a linear texture.
|
|
||||||
// Some drivers don't support this (e.g. adreno).
|
|
||||||
VkImageFormatProperties properties;
|
|
||||||
VkResult res = vkGetPhysicalDeviceImageFormatProperties(
|
|
||||||
g_object_cache->GetPhysicalDevice(), format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_LINEAR,
|
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, &properties);
|
|
||||||
if (res == VK_SUCCESS && width <= properties.maxExtent.width &&
|
|
||||||
height <= properties.maxExtent.height)
|
|
||||||
{
|
|
||||||
return StagingTexture2DLinear::Create(type, width, height, format);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Fall back to a buffer copy.
|
|
||||||
return StagingTexture2DBuffer::Create(type, width, height, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
StagingTexture2DLinear::StagingTexture2DLinear(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
|
||||||
VkFormat format, u32 stride, VkImage image,
|
|
||||||
VkDeviceMemory memory, VkDeviceSize size,
|
|
||||||
bool coherent)
|
|
||||||
: StagingTexture2D(type, width, height, format, stride), m_image(image), m_memory(memory),
|
|
||||||
m_size(size), m_layout(VK_IMAGE_LAYOUT_PREINITIALIZED), m_coherent(coherent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StagingTexture2DLinear::~StagingTexture2DLinear()
|
|
||||||
{
|
|
||||||
if (m_map_pointer)
|
|
||||||
Unmap();
|
|
||||||
|
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_memory);
|
|
||||||
g_command_buffer_mgr->DeferImageDestruction(m_image);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StagingTexture2DLinear::CopyFromImage(VkCommandBuffer command_buffer, VkImage image,
|
|
||||||
VkImageAspectFlags src_aspect, u32 x, u32 y, u32 width,
|
|
||||||
u32 height, u32 level, u32 layer)
|
|
||||||
{
|
|
||||||
// Prepare the buffer for copying.
|
|
||||||
// We don't care about the existing contents, so set to UNDEFINED.
|
|
||||||
VkImageMemoryBarrier before_transfer_barrier = {
|
|
||||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
0, // VkAccessFlags srcAccessMask
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
|
|
||||||
m_image, // VkImage image
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // VkImageSubresourceRange subresourceRange
|
|
||||||
};
|
|
||||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
|
||||||
&before_transfer_barrier);
|
|
||||||
|
|
||||||
// Issue the image copy, gpu -> host.
|
|
||||||
VkImageCopy copy_region = {
|
|
||||||
{src_aspect, level, layer, 1}, // VkImageSubresourceLayers srcSubresource
|
|
||||||
{static_cast<s32>(x), static_cast<s32>(y), 0}, // VkOffset3D srcOffset
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, // VkImageSubresourceLayers dstSubresource
|
|
||||||
{0, 0, 0}, // VkOffset3D dstOffset
|
|
||||||
{width, height, 1} // VkExtent3D extent
|
|
||||||
};
|
|
||||||
vkCmdCopyImage(command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
|
||||||
|
|
||||||
// Ensure writes are visible to the host.
|
|
||||||
VkImageMemoryBarrier visible_barrier = {
|
|
||||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask
|
|
||||||
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout
|
|
||||||
VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
|
|
||||||
m_image, // VkImage image
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // VkImageSubresourceRange subresourceRange
|
|
||||||
};
|
|
||||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
|
|
||||||
0, 0, nullptr, 0, nullptr, 1, &visible_barrier);
|
|
||||||
m_layout = VK_IMAGE_LAYOUT_GENERAL;
|
|
||||||
|
|
||||||
// Invalidate memory range if currently mapped.
|
|
||||||
if (m_map_pointer && !m_coherent)
|
|
||||||
{
|
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
|
||||||
m_map_offset, m_map_size};
|
|
||||||
vkInvalidateMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StagingTexture2DLinear::CopyToImage(VkCommandBuffer command_buffer, VkImage image,
|
|
||||||
VkImageAspectFlags dst_aspect, u32 x, u32 y, u32 width,
|
|
||||||
u32 height, u32 level, u32 layer)
|
|
||||||
{
|
|
||||||
// Flush memory range if currently mapped.
|
|
||||||
if (m_map_pointer && !m_coherent)
|
|
||||||
{
|
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
|
||||||
m_map_offset, m_map_size};
|
|
||||||
vkFlushMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure any writes to the image are visible to the GPU.
|
|
||||||
VkImageMemoryBarrier barrier = {
|
|
||||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask
|
|
||||||
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask
|
|
||||||
m_layout, // VkImageLayout oldLayout
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
|
|
||||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
|
|
||||||
m_image, // VkImage image
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // VkImageSubresourceRange subresourceRange
|
|
||||||
};
|
|
||||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
||||||
|
|
||||||
m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
|
||||||
|
|
||||||
// Issue the image copy, host -> gpu.
|
|
||||||
VkImageCopy copy_region = {
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, // VkImageSubresourceLayers srcSubresource
|
|
||||||
{0, 0, 0}, // VkOffset3D srcOffset
|
|
||||||
{dst_aspect, level, layer, 1}, // VkImageSubresourceLayers dstSubresource
|
|
||||||
{static_cast<s32>(x), static_cast<s32>(y), 0}, // VkOffset3D dstOffset
|
|
||||||
{width, height, 1} // VkExtent3D extent
|
|
||||||
};
|
|
||||||
vkCmdCopyImage(command_buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StagingTexture2DLinear::Map(VkDeviceSize offset /* = 0 */,
|
|
||||||
VkDeviceSize size /* = VK_WHOLE_SIZE */)
|
|
||||||
{
|
|
||||||
m_map_offset = offset;
|
|
||||||
if (size == VK_WHOLE_SIZE)
|
|
||||||
m_map_size = m_size - offset;
|
|
||||||
else
|
|
||||||
m_map_size = size;
|
|
||||||
|
|
||||||
_assert_(!m_map_pointer);
|
|
||||||
_assert_(m_map_offset + m_map_size <= m_size);
|
|
||||||
|
|
||||||
void* map_pointer;
|
|
||||||
VkResult res = vkMapMemory(g_vulkan_context->GetDevice(), m_memory, m_map_offset, m_map_size, 0,
|
|
||||||
&map_pointer);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkMapMemory failed: ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_map_pointer = reinterpret_cast<char*>(map_pointer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StagingTexture2DLinear::Unmap()
|
|
||||||
{
|
|
||||||
_assert_(m_map_pointer);
|
|
||||||
|
|
||||||
vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory);
|
|
||||||
m_map_pointer = nullptr;
|
|
||||||
m_map_offset = 0;
|
|
||||||
m_map_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<StagingTexture2D>
|
|
||||||
StagingTexture2DLinear::Create(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format)
|
|
||||||
{
|
|
||||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
VkImageCreateInfo create_info = {
|
|
||||||
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
0, // VkImageCreateFlags flags
|
|
||||||
VK_IMAGE_TYPE_2D, // VkImageType imageType
|
|
||||||
format, // VkFormat format
|
|
||||||
{width, height, 1}, // VkExtent3D extent
|
|
||||||
1, // uint32_t mipLevels
|
|
||||||
1, // uint32_t arrayLayers
|
|
||||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
|
|
||||||
VK_IMAGE_TILING_LINEAR, // VkImageTiling tiling
|
|
||||||
usage, // VkImageUsageFlags usage
|
|
||||||
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
|
|
||||||
0, // uint32_t queueFamilyIndexCount
|
|
||||||
nullptr, // const uint32_t* pQueueFamilyIndices
|
|
||||||
VK_IMAGE_LAYOUT_PREINITIALIZED // VkImageLayout initialLayout
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImage image;
|
|
||||||
VkResult res = vkCreateImage(g_vulkan_context->GetDevice(), &create_info, nullptr, &image);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateImage failed: ");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetImageMemoryRequirements(g_vulkan_context->GetDevice(), image, &memory_requirements);
|
|
||||||
|
|
||||||
bool is_coherent;
|
|
||||||
u32 memory_type_index;
|
|
||||||
if (type == STAGING_BUFFER_TYPE_READBACK)
|
|
||||||
{
|
|
||||||
memory_type_index =
|
|
||||||
g_vulkan_context->GetReadbackMemoryType(memory_requirements.memoryTypeBits, &is_coherent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memory_type_index =
|
|
||||||
g_vulkan_context->GetUploadMemoryType(memory_requirements.memoryTypeBits, &is_coherent);
|
|
||||||
}
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
memory_requirements.size, // VkDeviceSize allocationSize
|
|
||||||
memory_type_index // uint32_t memoryTypeIndex
|
|
||||||
};
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindImageMemory(g_vulkan_context->GetDevice(), image, memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindImageMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume tight packing. Is this correct?
|
|
||||||
u32 stride = width * Util::GetTexelSize(format);
|
|
||||||
return std::make_unique<StagingTexture2DLinear>(type, width, height, format, stride, image,
|
|
||||||
memory, memory_requirements.size, is_coherent);
|
|
||||||
}
|
|
||||||
|
|
||||||
StagingTexture2DBuffer::StagingTexture2DBuffer(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
|
||||||
VkFormat format, u32 stride, VkBuffer buffer,
|
|
||||||
VkDeviceMemory memory, VkDeviceSize size,
|
|
||||||
bool coherent)
|
|
||||||
: StagingTexture2D(type, width, height, format, stride), m_buffer(buffer), m_memory(memory),
|
|
||||||
m_size(size), m_coherent(coherent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StagingTexture2DBuffer::~StagingTexture2DBuffer()
|
|
||||||
{
|
|
||||||
if (m_map_pointer)
|
|
||||||
Unmap();
|
|
||||||
|
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_memory);
|
|
||||||
g_command_buffer_mgr->DeferBufferDestruction(m_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StagingTexture2DBuffer::CopyFromImage(VkCommandBuffer command_buffer, VkImage image,
|
|
||||||
VkImageAspectFlags src_aspect, u32 x, u32 y, u32 width,
|
|
||||||
u32 height, u32 level, u32 layer)
|
|
||||||
{
|
{
|
||||||
// Issue the image->buffer copy.
|
// Issue the image->buffer copy.
|
||||||
VkBufferImageCopy image_copy = {
|
VkBufferImageCopy image_copy = {
|
||||||
0, // VkDeviceSize bufferOffset
|
y * m_row_stride + x * m_texel_size, // VkDeviceSize bufferOffset
|
||||||
m_width, // uint32_t bufferRowLength
|
m_width, // uint32_t bufferRowLength
|
||||||
0, // uint32_t bufferImageHeight
|
0, // uint32_t bufferImageHeight
|
||||||
{src_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
|
{src_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
|
||||||
@ -382,42 +112,28 @@ void StagingTexture2DBuffer::CopyFromImage(VkCommandBuffer command_buffer, VkIma
|
|||||||
vkCmdCopyImageToBuffer(command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1,
|
vkCmdCopyImageToBuffer(command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1,
|
||||||
&image_copy);
|
&image_copy);
|
||||||
|
|
||||||
// Ensure the write has completed.
|
// Flush CPU and GPU caches if not coherent mapping.
|
||||||
VkDeviceSize copy_size = m_row_stride * height;
|
VkDeviceSize buffer_flush_offset = y * m_row_stride;
|
||||||
Util::BufferMemoryBarrier(command_buffer, m_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
|
VkDeviceSize buffer_flush_size = height * m_row_stride;
|
||||||
VK_ACCESS_HOST_READ_BIT, 0, copy_size, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
FlushGPUCache(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_PIPELINE_STAGE_HOST_BIT);
|
buffer_flush_offset, buffer_flush_size);
|
||||||
|
InvalidateCPUCache(buffer_flush_offset, buffer_flush_size);
|
||||||
// If we're still mapped, invalidate the mapped range
|
|
||||||
if (m_map_pointer && !m_coherent)
|
|
||||||
{
|
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
|
||||||
m_map_offset, m_map_size};
|
|
||||||
vkInvalidateMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingTexture2DBuffer::CopyToImage(VkCommandBuffer command_buffer, VkImage image,
|
void StagingTexture2D::CopyToImage(VkCommandBuffer command_buffer, VkImage image,
|
||||||
VkImageAspectFlags dst_aspect, u32 x, u32 y, u32 width,
|
VkImageAspectFlags dst_aspect, u32 x, u32 y, u32 width,
|
||||||
u32 height, u32 level, u32 layer)
|
u32 height, u32 level, u32 layer)
|
||||||
{
|
{
|
||||||
// If we're still mapped, flush the mapped range
|
// Flush CPU and GPU caches if not coherent mapping.
|
||||||
if (m_map_pointer && !m_coherent)
|
VkDeviceSize buffer_flush_offset = y * m_row_stride;
|
||||||
{
|
VkDeviceSize buffer_flush_size = height * m_row_stride;
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
FlushCPUCache(buffer_flush_offset, buffer_flush_size);
|
||||||
m_map_offset, m_map_size};
|
InvalidateGPUCache(command_buffer, VK_ACCESS_HOST_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
vkFlushMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
buffer_flush_offset, buffer_flush_size);
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure writes are visible to GPU.
|
// Issue the buffer->image copy.
|
||||||
VkDeviceSize copy_size = m_row_stride * height;
|
|
||||||
Util::BufferMemoryBarrier(command_buffer, m_buffer, VK_ACCESS_HOST_WRITE_BIT,
|
|
||||||
VK_ACCESS_TRANSFER_READ_BIT, 0, copy_size, VK_PIPELINE_STAGE_HOST_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
||||||
|
|
||||||
// Issue the buffer->image copy
|
|
||||||
VkBufferImageCopy image_copy = {
|
VkBufferImageCopy image_copy = {
|
||||||
0, // VkDeviceSize bufferOffset
|
y * m_row_stride + x * m_texel_size, // VkDeviceSize bufferOffset
|
||||||
m_width, // uint32_t bufferRowLength
|
m_width, // uint32_t bufferRowLength
|
||||||
0, // uint32_t bufferImageHeight
|
0, // uint32_t bufferImageHeight
|
||||||
{dst_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
|
{dst_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
|
||||||
@ -428,109 +144,21 @@ void StagingTexture2DBuffer::CopyToImage(VkCommandBuffer command_buffer, VkImage
|
|||||||
&image_copy);
|
&image_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StagingTexture2DBuffer::Map(VkDeviceSize offset /* = 0 */,
|
std::unique_ptr<StagingTexture2D> StagingTexture2D::Create(STAGING_BUFFER_TYPE type, u32 width,
|
||||||
VkDeviceSize size /* = VK_WHOLE_SIZE */)
|
u32 height, VkFormat format)
|
||||||
{
|
|
||||||
m_map_offset = offset;
|
|
||||||
if (size == VK_WHOLE_SIZE)
|
|
||||||
m_map_size = m_size - offset;
|
|
||||||
else
|
|
||||||
m_map_size = size;
|
|
||||||
|
|
||||||
_assert_(!m_map_pointer);
|
|
||||||
_assert_(m_map_offset + m_map_size <= m_size);
|
|
||||||
|
|
||||||
void* map_pointer;
|
|
||||||
VkResult res = vkMapMemory(g_vulkan_context->GetDevice(), m_memory, m_map_offset, m_map_size, 0,
|
|
||||||
&map_pointer);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkMapMemory failed: ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_map_pointer = reinterpret_cast<char*>(map_pointer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StagingTexture2DBuffer::Unmap()
|
|
||||||
{
|
|
||||||
_assert_(m_map_pointer);
|
|
||||||
|
|
||||||
vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory);
|
|
||||||
m_map_pointer = nullptr;
|
|
||||||
m_map_offset = 0;
|
|
||||||
m_map_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<StagingTexture2D>
|
|
||||||
StagingTexture2DBuffer::Create(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format)
|
|
||||||
{
|
{
|
||||||
// Assume tight packing.
|
// Assume tight packing.
|
||||||
u32 row_stride = Util::GetTexelSize(format) * width;
|
u32 stride = Util::GetTexelSize(format) * width;
|
||||||
u32 buffer_size = row_stride * height;
|
u32 size = stride * height;
|
||||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
VkBufferCreateInfo buffer_create_info = {
|
|
||||||
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
0, // VkBufferCreateFlags flags
|
|
||||||
buffer_size, // VkDeviceSize size
|
|
||||||
usage, // VkBufferUsageFlags usage
|
|
||||||
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
|
|
||||||
0, // uint32_t queueFamilyIndexCount
|
|
||||||
nullptr // const uint32_t* pQueueFamilyIndices
|
|
||||||
};
|
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
VkResult res =
|
|
||||||
vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, &buffer);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), buffer, &memory_requirements);
|
|
||||||
|
|
||||||
bool is_coherent;
|
|
||||||
u32 memory_type_index;
|
|
||||||
if (type == STAGING_BUFFER_TYPE_READBACK)
|
|
||||||
{
|
|
||||||
memory_type_index =
|
|
||||||
g_vulkan_context->GetReadbackMemoryType(memory_requirements.memoryTypeBits, &is_coherent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memory_type_index =
|
|
||||||
g_vulkan_context->GetUploadMemoryType(memory_requirements.memoryTypeBits, &is_coherent);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
memory_requirements.size, // VkDeviceSize allocationSize
|
|
||||||
memory_type_index // uint32_t memoryTypeIndex
|
|
||||||
};
|
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory);
|
bool coherent;
|
||||||
if (res != VK_SUCCESS)
|
if (!AllocateBuffer(type, size, usage, &buffer, &memory, &coherent))
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), buffer, memory, 0);
|
return std::make_unique<StagingTexture2D>(type, buffer, memory, size, coherent, width, height,
|
||||||
if (res != VK_SUCCESS)
|
format, stride);
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<StagingTexture2DBuffer>(type, width, height, format, row_stride, buffer,
|
|
||||||
memory, buffer_size, is_coherent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -9,29 +9,26 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoBackends/Vulkan/Constants.h"
|
#include "VideoBackends/Vulkan/Constants.h"
|
||||||
|
#include "VideoBackends/Vulkan/StagingBuffer.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
class StagingTexture2D
|
class StagingTexture2D final : public StagingBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StagingTexture2D(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format, u32 stride);
|
StagingTexture2D(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory,
|
||||||
virtual ~StagingTexture2D();
|
VkDeviceSize size, bool coherent, u32 width, u32 height, VkFormat format,
|
||||||
|
u32 stride);
|
||||||
|
~StagingTexture2D();
|
||||||
|
|
||||||
STAGING_BUFFER_TYPE GetType() const { return m_type; }
|
|
||||||
u32 GetWidth() const { return m_width; }
|
u32 GetWidth() const { return m_width; }
|
||||||
u32 GetHeight() const { return m_height; }
|
u32 GetHeight() const { return m_height; }
|
||||||
VkFormat GetFormat() const { return m_format; }
|
VkFormat GetFormat() const { return m_format; }
|
||||||
u32 GetRowStride() const { return m_row_stride; }
|
u32 GetRowStride() const { return m_row_stride; }
|
||||||
u32 GetTexelSize() const { return m_texel_size; }
|
u32 GetTexelSize() const { return m_texel_size; }
|
||||||
bool IsMapped() const { return m_map_pointer != nullptr; }
|
// Requires Map() to be called first.
|
||||||
const char* GetMapPointer() const { return m_map_pointer; }
|
|
||||||
char* GetMapPointer() { return m_map_pointer; }
|
|
||||||
VkDeviceSize GetMapOffset() const { return m_map_offset; }
|
|
||||||
VkDeviceSize GetMapSize() const { return m_map_size; }
|
|
||||||
const char* GetRowPointer(u32 row) const { return m_map_pointer + row * m_row_stride; }
|
const char* GetRowPointer(u32 row) const { return m_map_pointer + row * m_row_stride; }
|
||||||
char* GetRowPointer(u32 row) { return m_map_pointer + row * m_row_stride; }
|
char* GetRowPointer(u32 row) { return m_map_pointer + row * m_row_stride; }
|
||||||
// Requires Map() to be called first.
|
|
||||||
void ReadTexel(u32 x, u32 y, void* data, size_t data_size) const;
|
void ReadTexel(u32 x, u32 y, void* data, size_t data_size) const;
|
||||||
void WriteTexel(u32 x, u32 y, const void* data, size_t data_size);
|
void WriteTexel(u32 x, u32 y, const void* data, size_t data_size);
|
||||||
void ReadTexels(u32 x, u32 y, u32 width, u32 height, void* data, u32 data_stride) const;
|
void ReadTexels(u32 x, u32 y, u32 width, u32 height, void* data, u32 data_stride) const;
|
||||||
@ -39,89 +36,23 @@ public:
|
|||||||
|
|
||||||
// Assumes that image is in TRANSFER_SRC layout.
|
// Assumes that image is in TRANSFER_SRC layout.
|
||||||
// Results are not ready until command_buffer has been executed.
|
// Results are not ready until command_buffer has been executed.
|
||||||
virtual void CopyFromImage(VkCommandBuffer command_buffer, VkImage image,
|
void CopyFromImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags src_aspect,
|
||||||
VkImageAspectFlags src_aspect, u32 x, u32 y, u32 width, u32 height,
|
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer);
|
||||||
u32 level, u32 layer) = 0;
|
|
||||||
|
|
||||||
// Assumes that image is in TRANSFER_DST layout.
|
// Assumes that image is in TRANSFER_DST layout.
|
||||||
// Buffer is not safe for re-use until after command_buffer has been executed.
|
// Buffer is not safe for re-use until after command_buffer has been executed.
|
||||||
virtual void CopyToImage(VkCommandBuffer command_buffer, VkImage image,
|
void CopyToImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags dst_aspect,
|
||||||
VkImageAspectFlags dst_aspect, u32 x, u32 y, u32 width, u32 height,
|
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer);
|
||||||
u32 level, u32 layer) = 0;
|
|
||||||
virtual bool Map(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) = 0;
|
|
||||||
virtual void Unmap() = 0;
|
|
||||||
|
|
||||||
// Creates the optimal format of image copy.
|
// Creates the optimal format of image copy.
|
||||||
static std::unique_ptr<StagingTexture2D> Create(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
static std::unique_ptr<StagingTexture2D> Create(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
||||||
VkFormat format);
|
VkFormat format);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
STAGING_BUFFER_TYPE m_type;
|
|
||||||
u32 m_width;
|
u32 m_width;
|
||||||
u32 m_height;
|
u32 m_height;
|
||||||
VkFormat m_format;
|
VkFormat m_format;
|
||||||
u32 m_texel_size;
|
u32 m_texel_size;
|
||||||
u32 m_row_stride;
|
u32 m_row_stride;
|
||||||
|
|
||||||
char* m_map_pointer = nullptr;
|
|
||||||
VkDeviceSize m_map_offset = 0;
|
|
||||||
VkDeviceSize m_map_size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StagingTexture2DLinear : public StagingTexture2D
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StagingTexture2DLinear(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format,
|
|
||||||
u32 stride, VkImage image, VkDeviceMemory memory, VkDeviceSize size,
|
|
||||||
bool coherent);
|
|
||||||
|
|
||||||
~StagingTexture2DLinear();
|
|
||||||
|
|
||||||
void CopyFromImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags src_aspect,
|
|
||||||
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer) override;
|
|
||||||
|
|
||||||
void CopyToImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags dst_aspect,
|
|
||||||
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer) override;
|
|
||||||
|
|
||||||
bool Map(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) override;
|
|
||||||
void Unmap() override;
|
|
||||||
|
|
||||||
static std::unique_ptr<StagingTexture2D> Create(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
|
||||||
VkFormat format);
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkImage m_image;
|
|
||||||
VkDeviceMemory m_memory;
|
|
||||||
VkDeviceSize m_size;
|
|
||||||
VkImageLayout m_layout;
|
|
||||||
bool m_coherent;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StagingTexture2DBuffer : public StagingTexture2D
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StagingTexture2DBuffer(STAGING_BUFFER_TYPE type, u32 width, u32 height, VkFormat format,
|
|
||||||
u32 stride, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize size,
|
|
||||||
bool coherent);
|
|
||||||
|
|
||||||
~StagingTexture2DBuffer();
|
|
||||||
|
|
||||||
void CopyFromImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags src_aspect,
|
|
||||||
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer) override;
|
|
||||||
|
|
||||||
void CopyToImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags dst_aspect,
|
|
||||||
u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer) override;
|
|
||||||
|
|
||||||
bool Map(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) override;
|
|
||||||
void Unmap() override;
|
|
||||||
|
|
||||||
static std::unique_ptr<StagingTexture2D> Create(STAGING_BUFFER_TYPE type, u32 width, u32 height,
|
|
||||||
VkFormat format);
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkBuffer m_buffer;
|
|
||||||
VkDeviceMemory m_memory;
|
|
||||||
VkDeviceSize m_size;
|
|
||||||
bool m_coherent;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user