summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan
diff options
context:
space:
mode:
authorStenzek <stenzek@users.noreply.github.com>2017-12-01 14:24:06 +1000
committerGitHub <noreply@github.com>2017-12-01 14:24:06 +1000
commitcd68b3606cea8a7041751bda482170533bae3220 (patch)
tree4edef80bda42a82a50ff9f9e86d64aac38c8aff3 /Source/Core/VideoBackends/Vulkan
parent0773a48c6c990c488e70ff7c1f46713593440ddc (diff)
parent7f217a8bb24da323042081a02b65f84f9ce9761f (diff)
Merge pull request #6193 from stenzek/readbacks
Abstract Staging Textures - VideoCommon interface for texture readbacks/uploads
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan')
-rw-r--r--Source/Core/VideoBackends/Vulkan/CMakeLists.txt1
-rw-r--r--Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp6
-rw-r--r--Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp64
-rw-r--r--Source/Core/VideoBackends/Vulkan/FramebufferManager.h7
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp11
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.h4
-rw-r--r--Source/Core/VideoBackends/Vulkan/StagingBuffer.h2
-rw-r--r--Source/Core/VideoBackends/Vulkan/StagingTexture2D.cpp164
-rw-r--r--Source/Core/VideoBackends/Vulkan/StagingTexture2D.h58
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureCache.cpp5
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureCache.h2
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureConverter.cpp108
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureConverter.h12
-rw-r--r--Source/Core/VideoBackends/Vulkan/Util.cpp6
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.cpp330
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.h61
-rw-r--r--Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj2
17 files changed, 377 insertions, 466 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt
index f3d602afb6..25c12fb12c 100644
--- a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt
+++ b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt
@@ -11,7 +11,6 @@ set(SRCS
ShaderCompiler.cpp
StateTracker.cpp
StagingBuffer.cpp
- StagingTexture2D.cpp
StreamBuffer.cpp
SwapChain.cpp
Texture2D.cpp
diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp
index 51706fc33f..5d70d38584 100644
--- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp
+++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp
@@ -371,6 +371,12 @@ void CommandBufferManager::OnCommandBufferExecuted(size_t index)
FrameResources& resources = m_frame_resources[index];
// Fire fence tracking callbacks.
+ for (auto iter = m_fence_point_callbacks.begin(); iter != m_fence_point_callbacks.end();)
+ {
+ auto backup_iter = iter++;
+ backup_iter->second.second(resources.fence);
+ }
+
for (const auto& iter : m_fence_point_callbacks)
iter.second.second(resources.fence);
diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp
index 78689b9638..94f773fb94 100644
--- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp
+++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp
@@ -16,7 +16,6 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
-#include "VideoBackends/Vulkan/StagingTexture2D.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/StreamBuffer.h"
#include "VideoBackends/Vulkan/Texture2D.h"
@@ -698,7 +697,7 @@ u32 FramebufferManager::PeekEFBColor(u32 x, u32 y)
return 0;
u32 value;
- m_color_readback_texture->ReadTexel(x, y, &value, sizeof(value));
+ m_color_readback_texture->ReadTexel(x, y, &value);
return value;
}
@@ -711,7 +710,6 @@ bool FramebufferManager::PopulateColorReadbackTexture()
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
Texture2D* src_texture = m_efb_color_texture.get();
- VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
if (GetEFBSamples() > 1)
src_texture = ResolveEFBColorTexture(src_region);
@@ -750,9 +748,9 @@ bool FramebufferManager::PopulateColorReadbackTexture()
// Copy from EFB or copy texture to staging texture.
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
- m_color_readback_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- src_texture->GetImage(), src_aspect, 0, 0, EFB_WIDTH,
- EFB_HEIGHT, 0, 0);
+ static_cast<VKStagingTexture*>(m_color_readback_texture.get())
+ ->CopyFromTexture(src_texture, m_color_readback_texture->GetConfig().GetRect(), 0, 0,
+ m_color_readback_texture->GetConfig().GetRect());
// Restore original layout if we used the EFB as a source.
if (src_texture == m_efb_color_texture.get())
@@ -762,12 +760,7 @@ bool FramebufferManager::PopulateColorReadbackTexture()
}
// Wait until the copy is complete.
- Util::ExecuteCurrentCommandsAndRestoreState(false, true);
-
- // Map to host memory.
- if (!m_color_readback_texture->IsMapped() && !m_color_readback_texture->Map())
- return false;
-
+ m_color_readback_texture->Flush();
m_color_readback_texture_valid = true;
return true;
}
@@ -778,7 +771,7 @@ float FramebufferManager::PeekEFBDepth(u32 x, u32 y)
return 0.0f;
float value;
- m_depth_readback_texture->ReadTexel(x, y, &value, sizeof(value));
+ m_depth_readback_texture->ReadTexel(x, y, &value);
return value;
}
@@ -791,12 +784,10 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
Texture2D* src_texture = m_efb_depth_texture.get();
- VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
if (GetEFBSamples() > 1)
{
// EFB depth resolves are written out as color textures
src_texture = ResolveEFBDepthTexture(src_region);
- src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
}
if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT)
{
@@ -828,15 +819,14 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
// Use this as a source texture now.
src_texture = m_depth_copy_texture.get();
- src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
}
// Copy from EFB or copy texture to staging texture.
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
- m_depth_readback_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- src_texture->GetImage(), src_aspect, 0, 0, EFB_WIDTH,
- EFB_HEIGHT, 0, 0);
+ static_cast<VKStagingTexture*>(m_depth_readback_texture.get())
+ ->CopyFromTexture(src_texture, m_depth_readback_texture->GetConfig().GetRect(), 0, 0,
+ m_depth_readback_texture->GetConfig().GetRect());
// Restore original layout if we used the EFB as a source.
if (src_texture == m_efb_depth_texture.get())
@@ -846,12 +836,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
}
// Wait until the copy is complete.
- Util::ExecuteCurrentCommandsAndRestoreState(false, true);
-
- // Map to host memory.
- if (!m_depth_readback_texture->IsMapped() && !m_depth_readback_texture->Map())
- return false;
-
+ m_depth_readback_texture->Flush();
m_depth_readback_texture_valid = true;
return true;
}
@@ -1011,32 +996,27 @@ bool FramebufferManager::CreateReadbackTextures()
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
- m_color_readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, EFB_WIDTH,
- EFB_HEIGHT, EFB_COLOR_TEXTURE_FORMAT);
- if (!m_color_copy_texture || !m_color_readback_texture)
- {
- ERROR_LOG(VIDEO, "Failed to create EFB color readback texture");
- return false;
- }
-
m_depth_copy_texture =
Texture2D::Create(EFB_WIDTH, EFB_HEIGHT, 1, 1, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
- m_depth_readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, EFB_WIDTH,
- EFB_HEIGHT, EFB_DEPTH_TEXTURE_FORMAT);
- if (!m_depth_copy_texture || !m_depth_readback_texture)
+ if (!m_color_copy_texture || !m_depth_copy_texture)
{
- ERROR_LOG(VIDEO, "Failed to create EFB depth readback texture");
+ ERROR_LOG(VIDEO, "Failed to create EFB copy textures");
return false;
}
- // With Vulkan, we can leave these textures mapped and use invalidate/flush calls instead.
- if (!m_color_readback_texture->Map() || !m_depth_readback_texture->Map())
+ TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, AbstractTextureFormat::RGBA8,
+ false);
+ m_color_readback_texture =
+ g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config);
+ m_depth_readback_texture =
+ g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config);
+ if (!m_color_readback_texture || !m_depth_readback_texture)
{
- ERROR_LOG(VIDEO, "Failed to map EFB readback textures");
+ ERROR_LOG(VIDEO, "Failed to create EFB readback textures");
return false;
}
@@ -1113,7 +1093,7 @@ void FramebufferManager::PokeEFBColor(u32 x, u32 y, u32 color)
// Update the peek cache if it's valid, since we know the color of the pixel now.
if (m_color_readback_texture_valid)
- m_color_readback_texture->WriteTexel(x, y, &color, sizeof(color));
+ m_color_readback_texture->WriteTexel(x, y, &color);
}
void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth)
@@ -1126,7 +1106,7 @@ void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth)
// Update the peek cache if it's valid, since we know the color of the pixel now.
if (m_depth_readback_texture_valid)
- m_depth_readback_texture->WriteTexel(x, y, &depth, sizeof(depth));
+ m_depth_readback_texture->WriteTexel(x, y, &depth);
}
void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destination_list, u32 x,
diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h
index 0c1a160728..e765abc907 100644
--- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h
+++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h
@@ -13,9 +13,10 @@
#include "VideoCommon/FramebufferManagerBase.h"
#include "VideoCommon/RenderState.h"
+class AbstractStagingTexture;
+
namespace Vulkan
{
-class StagingTexture2D;
class StateTracker;
class StreamBuffer;
class Texture2D;
@@ -138,8 +139,8 @@ private:
VkFramebuffer m_depth_copy_framebuffer = VK_NULL_HANDLE;
// CPU-side EFB readback texture
- std::unique_ptr<StagingTexture2D> m_color_readback_texture;
- std::unique_ptr<StagingTexture2D> m_depth_readback_texture;
+ std::unique_ptr<AbstractStagingTexture> m_color_readback_texture;
+ std::unique_ptr<AbstractStagingTexture> m_depth_readback_texture;
bool m_color_readback_texture_valid = false;
bool m_depth_readback_texture_valid = false;
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
index 084e7a2880..742a525b98 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
@@ -159,6 +159,17 @@ void Renderer::DestroySemaphores()
}
}
+std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
+{
+ return VKTexture::Create(config);
+}
+
+std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
+ const TextureConfig& config)
+{
+ return VKStagingTexture::Create(type, config);
+}
+
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
{
u32 backbuffer_width = m_swap_chain->GetWidth();
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h
index e8b7952e7d..b3f8168347 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.h
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.h
@@ -32,6 +32,10 @@ public:
static Renderer* GetInstance();
+ std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
+ std::unique_ptr<AbstractStagingTexture>
+ CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
+
SwapChain* GetSwapChain() const { return m_swap_chain.get(); }
BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); }
bool Initialize();
diff --git a/Source/Core/VideoBackends/Vulkan/StagingBuffer.h b/Source/Core/VideoBackends/Vulkan/StagingBuffer.h
index 65cfb1c5c7..2ecb21cb22 100644
--- a/Source/Core/VideoBackends/Vulkan/StagingBuffer.h
+++ b/Source/Core/VideoBackends/Vulkan/StagingBuffer.h
@@ -59,11 +59,11 @@ public:
static std::unique_ptr<StagingBuffer> Create(STAGING_BUFFER_TYPE type, VkDeviceSize size,
VkBufferUsageFlags usage);
-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);
+protected:
STAGING_BUFFER_TYPE m_type;
VkBuffer m_buffer;
VkDeviceMemory m_memory;
diff --git a/Source/Core/VideoBackends/Vulkan/StagingTexture2D.cpp b/Source/Core/VideoBackends/Vulkan/StagingTexture2D.cpp
deleted file mode 100644
index ee726fc8f2..0000000000
--- a/Source/Core/VideoBackends/Vulkan/StagingTexture2D.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2016 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <cstring>
-
-#include "Common/Assert.h"
-
-#include "VideoBackends/Vulkan/CommandBufferManager.h"
-#include "VideoBackends/Vulkan/StagingTexture2D.h"
-#include "VideoBackends/Vulkan/Util.h"
-#include "VideoBackends/Vulkan/VulkanContext.h"
-
-namespace Vulkan
-{
-StagingTexture2D::StagingTexture2D(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory,
- VkDeviceSize size, bool coherent, u32 width, u32 height,
- VkFormat format, u32 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()
-{
-}
-
-void StagingTexture2D::ReadTexel(u32 x, u32 y, void* data, size_t data_size) const
-{
- _assert_(data_size >= m_texel_size);
-
- VkDeviceSize offset = y * m_row_stride + x * m_texel_size;
- VkDeviceSize map_offset = offset - m_map_offset;
- _assert_(offset >= m_map_offset && (map_offset + m_texel_size) <= (m_map_offset + m_map_size));
-
- const char* ptr = m_map_pointer + map_offset;
- memcpy(data, ptr, data_size);
-}
-
-void StagingTexture2D::WriteTexel(u32 x, u32 y, const void* data, size_t data_size)
-{
- _assert_(data_size >= m_texel_size);
-
- VkDeviceSize offset = y * m_row_stride + x * m_texel_size;
- VkDeviceSize map_offset = offset - m_map_offset;
- _assert_(offset >= m_map_offset && (map_offset + m_texel_size) <= (m_map_offset + m_map_size));
-
- char* ptr = m_map_pointer + map_offset;
- memcpy(ptr, data, data_size);
-}
-
-void StagingTexture2D::ReadTexels(u32 x, u32 y, u32 width, u32 height, void* data,
- u32 data_stride) const
-{
- const char* src_ptr = GetRowPointer(y);
-
- // Optimal path: same dimensions, same stride.
- _assert_((x + width) <= m_width && (y + height) <= m_height);
- if (x == 0 && width == m_width && m_row_stride == data_stride)
- {
- memcpy(data, src_ptr, m_row_stride * height);
- return;
- }
-
- u32 copy_size = std::min(width * m_texel_size, data_stride);
- char* dst_ptr = reinterpret_cast<char*>(data);
- for (u32 row = 0; row < height; row++)
- {
- memcpy(dst_ptr, src_ptr + (x * m_texel_size), copy_size);
- src_ptr += m_row_stride;
- dst_ptr += data_stride;
- }
-}
-
-void StagingTexture2D::WriteTexels(u32 x, u32 y, u32 width, u32 height, const void* data,
- u32 data_stride)
-{
- char* dst_ptr = GetRowPointer(y);
-
- // Optimal path: same dimensions, same stride.
- _assert_((x + width) <= m_width && (y + height) <= m_height);
- if (x == 0 && width == m_width && m_row_stride == data_stride)
- {
- memcpy(dst_ptr, data, m_row_stride * height);
- return;
- }
-
- u32 copy_size = std::min(width * m_texel_size, data_stride);
- const char* src_ptr = reinterpret_cast<const char*>(data);
- for (u32 row = 0; row < height; row++)
- {
- memcpy(dst_ptr + (x * m_texel_size), src_ptr, copy_size);
- dst_ptr += m_row_stride;
- src_ptr += data_stride;
- }
-}
-
-void StagingTexture2D::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.
- VkBufferImageCopy image_copy = {
- y * m_row_stride + x * m_texel_size, // VkDeviceSize bufferOffset
- m_width, // uint32_t bufferRowLength
- 0, // uint32_t bufferImageHeight
- {src_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
- {static_cast<s32>(x), static_cast<s32>(y), 0}, // VkOffset3D imageOffset
- {width, height, 1} // VkExtent3D imageExtent
- };
- vkCmdCopyImageToBuffer(command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1,
- &image_copy);
-
- // Flush CPU and GPU caches if not coherent mapping.
- VkDeviceSize buffer_flush_offset = y * m_row_stride;
- VkDeviceSize buffer_flush_size = height * m_row_stride;
- FlushGPUCache(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
- buffer_flush_offset, buffer_flush_size);
- InvalidateCPUCache(buffer_flush_offset, buffer_flush_size);
-}
-
-void StagingTexture2D::CopyToImage(VkCommandBuffer command_buffer, VkImage image,
- VkImageAspectFlags dst_aspect, u32 x, u32 y, u32 width,
- u32 height, u32 level, u32 layer)
-{
- // Flush CPU and GPU caches if not coherent mapping.
- VkDeviceSize buffer_flush_offset = y * m_row_stride;
- VkDeviceSize buffer_flush_size = height * m_row_stride;
- FlushCPUCache(buffer_flush_offset, buffer_flush_size);
- InvalidateGPUCache(command_buffer, VK_ACCESS_HOST_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
- buffer_flush_offset, buffer_flush_size);
-
- // Issue the buffer->image copy.
- VkBufferImageCopy image_copy = {
- y * m_row_stride + x * m_texel_size, // VkDeviceSize bufferOffset
- m_width, // uint32_t bufferRowLength
- 0, // uint32_t bufferImageHeight
- {dst_aspect, level, layer, 1}, // VkImageSubresourceLayers imageSubresource
- {static_cast<s32>(x), static_cast<s32>(y), 0}, // VkOffset3D imageOffset
- {width, height, 1} // VkExtent3D imageExtent
- };
- vkCmdCopyBufferToImage(command_buffer, m_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
- &image_copy);
-}
-
-std::unique_ptr<StagingTexture2D> StagingTexture2D::Create(STAGING_BUFFER_TYPE type, u32 width,
- u32 height, VkFormat format)
-{
- // Assume tight packing.
- u32 stride = Util::GetTexelSize(format) * width;
- u32 size = stride * height;
- VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-
- VkBuffer buffer;
- VkDeviceMemory memory;
- bool coherent;
- if (!AllocateBuffer(type, size, usage, &buffer, &memory, &coherent))
- return nullptr;
-
- return std::make_unique<StagingTexture2D>(type, buffer, memory, size, coherent, width, height,
- format, stride);
-}
-} // namespace Vulkan
diff --git a/Source/Core/VideoBackends/Vulkan/StagingTexture2D.h b/Source/Core/VideoBackends/Vulkan/StagingTexture2D.h
deleted file mode 100644
index 74dbb8cf07..0000000000
--- a/Source/Core/VideoBackends/Vulkan/StagingTexture2D.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <cstddef>
-#include <memory>
-
-#include "Common/CommonTypes.h"
-#include "VideoBackends/Vulkan/Constants.h"
-#include "VideoBackends/Vulkan/StagingBuffer.h"
-
-namespace Vulkan
-{
-class StagingTexture2D final : public StagingBuffer
-{
-public:
- StagingTexture2D(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory,
- VkDeviceSize size, bool coherent, u32 width, u32 height, VkFormat format,
- u32 stride);
- ~StagingTexture2D();
-
- u32 GetWidth() const { return m_width; }
- u32 GetHeight() const { return m_height; }
- VkFormat GetFormat() const { return m_format; }
- u32 GetRowStride() const { return m_row_stride; }
- u32 GetTexelSize() const { return m_texel_size; }
- // Requires Map() to be called first.
- 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; }
- 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 ReadTexels(u32 x, u32 y, u32 width, u32 height, void* data, u32 data_stride) const;
- void WriteTexels(u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride);
-
- // Assumes that image is in TRANSFER_SRC layout.
- // Results are not ready until command_buffer has been executed.
- void CopyFromImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags src_aspect,
- u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer);
-
- // Assumes that image is in TRANSFER_DST layout.
- // Buffer is not safe for re-use until after command_buffer has been executed.
- void CopyToImage(VkCommandBuffer command_buffer, VkImage image, VkImageAspectFlags dst_aspect,
- u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer);
-
- // Creates the optimal format of image copy.
- static std::unique_ptr<StagingTexture2D> Create(STAGING_BUFFER_TYPE type, u32 width, u32 height,
- VkFormat format);
-
-protected:
- u32 m_width;
- u32 m_height;
- VkFormat m_format;
- u32 m_texel_size;
- u32 m_row_stride;
-};
-}
diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
index 1d8221f646..5a396ee4b2 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
+++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
@@ -178,11 +178,6 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u
}
}
-std::unique_ptr<AbstractTexture> TextureCache::CreateTexture(const TextureConfig& config)
-{
- return VKTexture::Create(config);
-}
-
bool TextureCache::CreateRenderPasses()
{
static constexpr VkAttachmentDescription update_attachment = {
diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h
index 9bfa2da04e..12bf088ad1 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureCache.h
+++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h
@@ -31,8 +31,6 @@ public:
bool CompileShaders() override;
void DeleteShaders() override;
- std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
-
void ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette,
TLUTFormat format) override;
diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
index b8ac91d06b..72995c7a4b 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
+++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
@@ -19,7 +19,6 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/FramebufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
-#include "VideoBackends/Vulkan/StagingTexture2D.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/StreamBuffer.h"
#include "VideoBackends/Vulkan/Texture2D.h"
@@ -67,9 +66,6 @@ TextureConverter::~TextureConverter()
if (m_encoding_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr);
- if (m_encoding_render_framebuffer != VK_NULL_HANDLE)
- vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr);
-
for (auto& it : m_encoding_shaders)
vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr);
@@ -111,12 +107,6 @@ bool TextureConverter::Initialize()
return false;
}
- if (!CreateEncodingDownloadTexture())
- {
- PanicAlert("Failed to create download texture");
- return false;
- }
-
if (!CreateDecodingTexture())
{
PanicAlert("Failed to create decoding texture");
@@ -245,8 +235,10 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
// Can't do our own draw within a render pass.
StateTracker::GetInstance()->EndRenderPass();
- m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ static_cast<VKTexture*>(m_encoding_render_texture.get())
+ ->GetRawTexIdentifier()
+ ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
@@ -276,23 +268,15 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
render_height);
VkRect2D render_region = {{0, 0}, {render_width, render_height}};
- draw.BeginRenderPass(m_encoding_render_framebuffer, render_region);
+ draw.BeginRenderPass(static_cast<VKTexture*>(m_encoding_render_texture.get())->GetFramebuffer(),
+ render_region);
draw.DrawWithoutVertexBuffer(4);
draw.EndRenderPass();
- // Transition the image before copying
- m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
- m_encoding_download_texture->CopyFromImage(
- g_command_buffer_mgr->GetCurrentCommandBuffer(), m_encoding_render_texture->GetImage(),
- VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, render_width, render_height, 0, 0);
-
- // Block until the GPU has finished copying to the staging texture.
- Util::ExecuteCurrentCommandsAndRestoreState(false, true);
-
- // Copy from staging texture to the final destination, adjusting pitch if necessary.
- m_encoding_download_texture->ReadTexels(0, 0, render_width, render_height, dest_ptr,
- memory_stride);
+ MathUtil::Rectangle<int> copy_rect(0, 0, render_width, render_height);
+ m_encoding_readback_texture->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0,
+ copy_rect);
+ m_encoding_readback_texture->ReadTexels(copy_rect, dest_ptr, memory_stride);
}
void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u32 dst_stride,
@@ -304,8 +288,9 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u
// Borrow framebuffer from EFB2RAM encoder.
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- m_encoding_render_texture->TransitionToLayout(command_buffer,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ static_cast<VKTexture*>(m_encoding_render_texture.get())
+ ->GetRawTexIdentifier()
+ ->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Use fragment shader to convert RGBA to YUYV.
// Use linear sampler for downscaling. This texture is in BGRA order, so the data is already in
@@ -317,7 +302,8 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u
m_encoding_render_pass, g_shader_cache->GetPassthroughVertexShader(),
VK_NULL_HANDLE, m_rgb_to_yuyv_shader);
VkRect2D region = {{0, 0}, {output_width, dst_height}};
- draw.BeginRenderPass(m_encoding_render_framebuffer, region);
+ draw.BeginRenderPass(static_cast<VKTexture*>(m_encoding_render_texture.get())->GetFramebuffer(),
+ region);
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetLinearSampler());
draw.DrawQuad(0, 0, static_cast<int>(output_width), static_cast<int>(dst_height), src_rect.left,
src_rect.top, 0, src_rect.GetWidth(), src_rect.GetHeight(),
@@ -325,18 +311,11 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u
static_cast<int>(src_texture->GetHeight()));
draw.EndRenderPass();
- // Render pass transitions to TRANSFER_SRC.
- m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
-
// Copy from encoding texture to download buffer.
- m_encoding_download_texture->CopyFromImage(command_buffer, m_encoding_render_texture->GetImage(),
- VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, output_width,
- dst_height, 0, 0);
- Util::ExecuteCurrentCommandsAndRestoreState(false, true);
-
- // Finally, copy to guest memory. This may have a different stride.
- m_encoding_download_texture->ReadTexels(0, 0, output_width, dst_height, dst_ptr, dst_stride);
+ MathUtil::Rectangle<int> copy_rect(0, 0, output_width, dst_height);
+ m_encoding_readback_texture->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0,
+ copy_rect);
+ m_encoding_readback_texture->ReadTexels(copy_rect, dst_ptr, dst_stride);
}
void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const void* src_ptr,
@@ -734,10 +713,10 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params)
bool TextureConverter::CreateEncodingRenderPass()
{
VkAttachmentDescription attachments[] = {
- {0, ENCODING_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
+ {0, Util::GetVkFormatForHostTextureFormat(ENCODING_TEXTURE_FORMAT), VK_SAMPLE_COUNT_1_BIT,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkAttachmentReference color_attachment_references[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
@@ -769,43 +748,14 @@ bool TextureConverter::CreateEncodingRenderPass()
bool TextureConverter::CreateEncodingTexture()
{
- m_encoding_render_texture = Texture2D::Create(
- ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, ENCODING_TEXTURE_FORMAT,
- VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
- if (!m_encoding_render_texture)
- return false;
+ TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1,
+ ENCODING_TEXTURE_FORMAT, true);
- VkImageView framebuffer_attachments[] = {m_encoding_render_texture->GetView()};
- VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- nullptr,
- 0,
- m_encoding_render_pass,
- static_cast<u32>(ArraySize(framebuffer_attachments)),
- framebuffer_attachments,
- m_encoding_render_texture->GetWidth(),
- m_encoding_render_texture->GetHeight(),
- m_encoding_render_texture->GetLayers()};
-
- VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
- &m_encoding_render_framebuffer);
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
- return false;
- }
-
- return true;
-}
-
-bool TextureConverter::CreateEncodingDownloadTexture()
-{
- m_encoding_download_texture =
- StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, ENCODING_TEXTURE_WIDTH,
- ENCODING_TEXTURE_HEIGHT, ENCODING_TEXTURE_FORMAT);
+ m_encoding_render_texture = g_renderer->CreateTexture(config);
+ m_encoding_readback_texture =
+ g_renderer->CreateStagingTexture(StagingTextureType::Readback, config);
- return m_encoding_download_texture && m_encoding_download_texture->Map();
+ return m_encoding_render_texture && m_encoding_readback_texture;
}
bool TextureConverter::CreateDecodingTexture()
diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.h b/Source/Core/VideoBackends/Vulkan/TextureConverter.h
index 1a62590019..3adb26c5b7 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureConverter.h
+++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.h
@@ -16,6 +16,9 @@
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoCommon.h"
+class AbstractTexture;
+class AbstractStagingTexture;
+
namespace Vulkan
{
class StagingTexture2D;
@@ -58,7 +61,7 @@ public:
private:
static const u32 ENCODING_TEXTURE_WIDTH = EFB_WIDTH * 4;
static const u32 ENCODING_TEXTURE_HEIGHT = 1024;
- static const VkFormat ENCODING_TEXTURE_FORMAT = VK_FORMAT_B8G8R8A8_UNORM;
+ static const AbstractTextureFormat ENCODING_TEXTURE_FORMAT = AbstractTextureFormat::BGRA8;
static const size_t NUM_PALETTE_CONVERSION_SHADERS = 3;
// Maximum size of a texture based on BP registers.
@@ -75,8 +78,6 @@ private:
bool CreateEncodingRenderPass();
bool CreateEncodingTexture();
- bool CreateEncodingDownloadTexture();
-
bool CreateDecodingTexture();
bool CompileYUYVConversionShaders();
@@ -106,10 +107,9 @@ private:
// Texture encoding - RGBA8->GX format in memory
std::map<EFBCopyParams, VkShaderModule> m_encoding_shaders;
+ std::unique_ptr<AbstractTexture> m_encoding_render_texture;
+ std::unique_ptr<AbstractStagingTexture> m_encoding_readback_texture;
VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE;
- std::unique_ptr<Texture2D> m_encoding_render_texture;
- VkFramebuffer m_encoding_render_framebuffer = VK_NULL_HANDLE;
- std::unique_ptr<StagingTexture2D> m_encoding_download_texture;
// Texture decoding - GX format in memory->RGBA8
struct TextureDecodingPipeline
diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp
index 221fa97cda..e74435e6d6 100644
--- a/Source/Core/VideoBackends/Vulkan/Util.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Util.cpp
@@ -107,7 +107,13 @@ VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format)
return VK_FORMAT_BC7_UNORM_BLOCK;
case AbstractTextureFormat::RGBA8:
+ return VK_FORMAT_R8G8B8A8_UNORM;
+
+ case AbstractTextureFormat::BGRA8:
+ return VK_FORMAT_B8G8R8A8_UNORM;
+
default:
+ PanicAlert("Unhandled texture format.");
return VK_FORMAT_R8G8B8A8_UNORM;
}
}
diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
index cbb6e0c063..59be6a0eba 100644
--- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp
@@ -14,7 +14,7 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/FramebufferManager.h"
-#include "VideoBackends/Vulkan/StagingTexture2D.h"
+#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/Texture2D.h"
#include "VideoBackends/Vulkan/Util.h"
@@ -113,60 +113,13 @@ void VKTexture::Bind(unsigned int stage)
StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView());
}
-std::optional<AbstractTexture::RawTextureInfo> VKTexture::MapFullImpl()
+void VKTexture::CopyRectangleFromTexture(const AbstractTexture* src,
+ const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
+ u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
+ u32 dst_layer, u32 dst_level)
{
- // No support for optimization of full copy
- return MapRegionImpl(0, 0, 0, m_config.width, m_config.height);
-}
-
-std::optional<AbstractTexture::RawTextureInfo> VKTexture::MapRegionImpl(u32 level, u32 x, u32 y,
- u32 width, u32 height)
-{
- m_staging_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height,
- TEXTURECACHE_TEXTURE_FORMAT);
-
- // Transition image to transfer source, and invalidate the current state,
- // since we'll be executing the command buffer.
- m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
- StateTracker::GetInstance()->EndRenderPass();
-
- // Copy to download buffer.
- m_staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, x, y, width,
- height, level, 0);
+ Texture2D* src_texture = static_cast<const VKTexture*>(src)->GetRawTexIdentifier();
- // Restore original state of texture.
- m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-
- // Block until the GPU has finished copying to the staging texture.
- Util::ExecuteCurrentCommandsAndRestoreState(false, true);
-
- // Map the staging texture so we can copy the contents out.
- if (!m_staging_texture->Map())
- {
- PanicAlert("Failed to map staging texture");
- return {};
- }
-
- return AbstractTexture::RawTextureInfo{reinterpret_cast<u8*>(m_staging_texture->GetMapPointer()),
- static_cast<u32>(m_staging_texture->GetRowStride()), width,
- height};
-}
-
-void VKTexture::Unmap()
-{
- if (!m_staging_texture)
- return;
-
- m_staging_texture->Unmap();
-}
-
-void VKTexture::CopyTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,
- Texture2D* src_texture,
- const MathUtil::Rectangle<int>& src_rect)
-{
_assert_msg_(VIDEO, static_cast<u32>(src_rect.GetWidth()) <= src_texture->GetWidth() &&
static_cast<u32>(src_rect.GetHeight()) <= src_texture->GetHeight(),
"Source rect is too large for CopyRectangleFromTexture");
@@ -176,15 +129,11 @@ void VKTexture::CopyTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,
"Dest rect is too large for CopyRectangleFromTexture");
VkImageCopy image_copy = {
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
- src_texture->GetLayers()}, // VkImageSubresourceLayers srcSubresource
- {src_rect.left, src_rect.top, 0}, // VkOffset3D srcOffset
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, // VkImageSubresourceLayers dstSubresource
- m_config.layers},
- {dst_rect.left, dst_rect.top, 0}, // VkOffset3D dstOffset
- {static_cast<uint32_t>(src_rect.GetWidth()), static_cast<uint32_t>(src_rect.GetHeight()),
- 1} // VkExtent3D extent
- };
+ {VK_IMAGE_ASPECT_COLOR_BIT, src_level, src_layer, src_texture->GetLayers()},
+ {src_rect.left, src_rect.top, 0},
+ {VK_IMAGE_ASPECT_COLOR_BIT, dst_level, dst_layer, m_config.layers},
+ {dst_rect.left, dst_rect.top, 0},
+ {static_cast<uint32_t>(src_rect.GetWidth()), static_cast<uint32_t>(src_rect.GetHeight()), 1}};
// Must be called outside of a render pass.
StateTracker::GetInstance()->EndRenderPass();
@@ -197,12 +146,20 @@ void VKTexture::CopyTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,
vkCmdCopyImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), src_texture->GetImage(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_texture->GetImage(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
+
+ // Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound.
+ src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
-void VKTexture::ScaleTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,
- Texture2D* src_texture,
- const MathUtil::Rectangle<int>& src_rect)
+void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
+ const MathUtil::Rectangle<int>& src_rect,
+ const MathUtil::Rectangle<int>& dst_rect)
{
+ Texture2D* src_texture = static_cast<const VKTexture*>(source)->GetRawTexIdentifier();
+
// Can't do this within a game render pass.
StateTracker::GetInstance()->EndRenderPass();
StateTracker::GetInstance()->SetPendingRebind();
@@ -235,27 +192,10 @@ void VKTexture::ScaleTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,
static_cast<int>(src_texture->GetWidth()),
static_cast<int>(src_texture->GetHeight()));
draw.EndRenderPass();
-}
-
-void VKTexture::CopyRectangleFromTexture(const AbstractTexture* source,
- const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect)
-{
- auto* raw_source_texture = static_cast<const VKTexture*>(source)->GetRawTexIdentifier();
- CopyRectangleFromTexture(raw_source_texture, srcrect, dstrect);
-}
-
-void VKTexture::CopyRectangleFromTexture(Texture2D* source, const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect)
-{
- if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight())
- CopyTextureRectangle(dstrect, source, srcrect);
- else
- ScaleTextureRectangle(dstrect, source, srcrect);
// Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound.
- source->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
@@ -291,7 +231,7 @@ void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8*
u32 upload_alignment = static_cast<u32>(g_vulkan_context->GetBufferImageGranularity());
u32 block_size = Util::GetBlockSize(m_texture->GetFormat());
u32 num_rows = Common::AlignUp(height, block_size) / block_size;
- size_t source_pitch = CalculateHostTextureLevelPitch(m_config.format, row_length);
+ size_t source_pitch = CalculateStrideForFormat(m_config.format, row_length);
size_t upload_size = source_pitch * num_rows;
std::unique_ptr<StagingBuffer> temp_buffer;
VkBuffer upload_buffer;
@@ -356,4 +296,224 @@ void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8*
}
}
+VKStagingTexture::VKStagingTexture(StagingTextureType type, const TextureConfig& config,
+ std::unique_ptr<StagingBuffer> buffer)
+ : AbstractStagingTexture(type, config), m_staging_buffer(std::move(buffer))
+{
+}
+
+VKStagingTexture::~VKStagingTexture()
+{
+ if (m_needs_flush)
+ VKStagingTexture::Flush();
+}
+
+std::unique_ptr<VKStagingTexture> VKStagingTexture::Create(StagingTextureType type,
+ const TextureConfig& config)
+{
+ size_t stride = config.GetStride();
+ size_t buffer_size = stride * static_cast<size_t>(config.height);
+
+ STAGING_BUFFER_TYPE buffer_type;
+ VkImageUsageFlags buffer_usage;
+ if (type == StagingTextureType::Readback)
+ {
+ buffer_type = STAGING_BUFFER_TYPE_READBACK;
+ buffer_usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ }
+ else if (type == StagingTextureType::Upload)
+ {
+ buffer_type = STAGING_BUFFER_TYPE_UPLOAD;
+ buffer_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ }
+ else
+ {
+ buffer_type = STAGING_BUFFER_TYPE_READBACK;
+ buffer_usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ }
+
+ VkBuffer buffer;
+ VkDeviceMemory memory;
+ bool coherent;
+ if (!StagingBuffer::AllocateBuffer(buffer_type, buffer_size, buffer_usage, &buffer, &memory,
+ &coherent))
+ {
+ return nullptr;
+ }
+
+ std::unique_ptr<StagingBuffer> staging_buffer =
+ std::make_unique<StagingBuffer>(buffer_type, buffer, memory, buffer_size, coherent);
+ std::unique_ptr<VKStagingTexture> staging_tex = std::unique_ptr<VKStagingTexture>(
+ new VKStagingTexture(type, config, std::move(staging_buffer)));
+
+ // Use persistent mapping.
+ if (!staging_tex->m_staging_buffer->Map())
+ return nullptr;
+ staging_tex->m_map_pointer = staging_tex->m_staging_buffer->GetMapPointer();
+ staging_tex->m_map_stride = stride;
+ return staging_tex;
+}
+
+void VKStagingTexture::CopyFromTexture(const AbstractTexture* src,
+ const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
+ u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
+{
+ _assert_(m_type == StagingTextureType::Readback);
+ _assert_(src_rect.GetWidth() == dst_rect.GetWidth() &&
+ src_rect.GetHeight() == dst_rect.GetHeight());
+ _assert_(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
+ src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetConfig().height);
+ _assert_(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= m_config.width &&
+ dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= m_config.height);
+
+ Texture2D* src_tex = static_cast<const VKTexture*>(src)->GetRawTexIdentifier();
+ CopyFromTexture(src_tex, src_rect, src_layer, src_level, dst_rect);
+}
+
+void VKStagingTexture::CopyFromTexture(Texture2D* src, const MathUtil::Rectangle<int>& src_rect,
+ u32 src_layer, u32 src_level,
+ const MathUtil::Rectangle<int>& dst_rect)
+{
+ if (m_needs_flush)
+ {
+ // Drop copy before reusing it.
+ g_command_buffer_mgr->RemoveFencePointCallback(this);
+ m_flush_fence = VK_NULL_HANDLE;
+ m_needs_flush = false;
+ }
+
+ VkImageLayout old_layout = src->GetLayout();
+ src->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ // Issue the image->buffer copy, but delay it for now.
+ VkBufferImageCopy image_copy = {};
+ VkImageAspectFlags aspect =
+ Util::IsDepthFormat(src->GetFormat()) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
+ image_copy.bufferOffset =
+ static_cast<VkDeviceSize>(static_cast<size_t>(dst_rect.top) * m_config.GetStride() +
+ static_cast<size_t>(dst_rect.left) * m_texel_size);
+ image_copy.bufferRowLength = static_cast<u32>(m_config.width);
+ image_copy.bufferImageHeight = 0;
+ image_copy.imageSubresource = {aspect, src_level, src_layer, 1};
+ image_copy.imageOffset = {src_rect.left, src_rect.top, 0};
+ image_copy.imageExtent = {static_cast<u32>(src_rect.GetWidth()),
+ static_cast<u32>(src_rect.GetHeight()), 1u};
+ vkCmdCopyImageToBuffer(g_command_buffer_mgr->GetCurrentCommandBuffer(), src->GetImage(),
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_staging_buffer->GetBuffer(), 1,
+ &image_copy);
+
+ // Restore old source texture layout.
+ src->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), old_layout);
+
+ m_needs_flush = true;
+ g_command_buffer_mgr->AddFencePointCallback(this,
+ [this](VkCommandBuffer buf, VkFence fence) {
+ _assert_(m_needs_flush);
+ m_flush_fence = fence;
+ },
+ [this](VkFence fence) {
+ m_flush_fence = VK_NULL_HANDLE;
+ m_needs_flush = false;
+ g_command_buffer_mgr->RemoveFencePointCallback(
+ this);
+ });
+}
+
+void VKStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect, AbstractTexture* dst,
+ const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
+ u32 dst_level)
+{
+ _assert_(m_type == StagingTextureType::Upload);
+ _assert_(src_rect.GetWidth() == dst_rect.GetWidth() &&
+ src_rect.GetHeight() == dst_rect.GetHeight());
+ _assert_(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
+ src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= m_config.height);
+ _assert_(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
+ dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
+
+ if (m_needs_flush)
+ {
+ // Drop copy before reusing it.
+ g_command_buffer_mgr->RemoveFencePointCallback(this);
+ m_flush_fence = VK_NULL_HANDLE;
+ m_needs_flush = false;
+ }
+
+ // Flush caches before copying.
+ m_staging_buffer->FlushCPUCache();
+
+ Texture2D* dst_tex = static_cast<const VKTexture*>(dst)->GetRawTexIdentifier();
+ VkImageLayout old_layout = dst_tex->GetLayout();
+ dst_tex->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ // Issue the image->buffer copy, but delay it for now.
+ VkBufferImageCopy image_copy = {};
+ image_copy.bufferOffset =
+ static_cast<VkDeviceSize>(static_cast<size_t>(src_rect.top) * m_config.GetStride() +
+ static_cast<size_t>(src_rect.left) * m_texel_size);
+ image_copy.bufferRowLength = static_cast<u32>(m_config.width);
+ image_copy.bufferImageHeight = 0;
+ image_copy.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, dst_level, dst_layer, 1};
+ image_copy.imageOffset = {dst_rect.left, dst_rect.top, 0};
+ image_copy.imageExtent = {static_cast<u32>(dst_rect.GetWidth()),
+ static_cast<u32>(dst_rect.GetHeight()), 1u};
+ vkCmdCopyBufferToImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ m_staging_buffer->GetBuffer(), dst_tex->GetImage(),
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
+
+ // Restore old source texture layout.
+ dst_tex->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), old_layout);
+
+ m_needs_flush = true;
+ g_command_buffer_mgr->AddFencePointCallback(this,
+ [this](VkCommandBuffer buf, VkFence fence) {
+ _assert_(m_needs_flush);
+ m_flush_fence = fence;
+ },
+ [this](VkFence fence) {
+ m_flush_fence = VK_NULL_HANDLE;
+ m_needs_flush = false;
+ g_command_buffer_mgr->RemoveFencePointCallback(
+ this);
+ });
+}
+
+bool VKStagingTexture::Map()
+{
+ // Always mapped.
+ return true;
+}
+
+void VKStagingTexture::Unmap()
+{
+ // Always mapped.
+}
+
+void VKStagingTexture::Flush()
+{
+ if (!m_needs_flush)
+ return;
+
+ // Either of the below two calls will cause the callback to fire.
+ g_command_buffer_mgr->RemoveFencePointCallback(this);
+ if (m_flush_fence != VK_NULL_HANDLE)
+ {
+ // WaitForFence should fire the callback.
+ g_command_buffer_mgr->WaitForFence(m_flush_fence);
+ }
+ else
+ {
+ // We don't have a fence, and are pending. That means the readback is in the current
+ // command buffer, and must execute it to populate the staging texture.
+ Util::ExecuteCurrentCommandsAndRestoreState(false, true);
+ }
+ m_needs_flush = false;
+
+ // For readback textures, invalidate the CPU cache as there is new data there.
+ if (m_type == StagingTextureType::Readback)
+ m_staging_buffer->InvalidateCPUCache();
+}
+
} // namespace Vulkan
diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h
index 61ffae242c..426f29973d 100644
--- a/Source/Core/VideoBackends/Vulkan/VKTexture.h
+++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h
@@ -7,10 +7,12 @@
#include <memory>
#include <vulkan/vulkan.h>
+#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
namespace Vulkan
{
+class StagingBuffer;
class Texture2D;
class VKTexture final : public AbstractTexture
@@ -20,13 +22,16 @@ public:
~VKTexture();
void Bind(unsigned int stage) override;
- void Unmap() override;
- void CopyRectangleFromTexture(const AbstractTexture* source,
- const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect) override;
- void CopyRectangleFromTexture(Texture2D* source, const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect);
+ void CopyRectangleFromTexture(const AbstractTexture* src,
+ const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
+ u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
+ u32 dst_layer, u32 dst_level) override;
+ void ScaleRectangleFromTexture(const AbstractTexture* source,
+ const MathUtil::Rectangle<int>& src_rect,
+ const MathUtil::Rectangle<int>& dst_rect);
+ void ScaleRectangleFromTexture(Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect,
+ const MathUtil::Rectangle<int>& dst_rect);
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
size_t buffer_size) override;
@@ -39,21 +44,41 @@ private:
VKTexture(const TextureConfig& tex_config, std::unique_ptr<Texture2D> texture,
VkFramebuffer framebuffer);
- // Copies the contents of a texture using vkCmdCopyImage
- void CopyTextureRectangle(const MathUtil::Rectangle<int>& dst_rect, Texture2D* src_texture,
- const MathUtil::Rectangle<int>& src_rect);
+ std::unique_ptr<Texture2D> m_texture;
+ VkFramebuffer m_framebuffer;
+};
- // Copies (and optionally scales) the contents of a texture using a framgent shader.
- void ScaleTextureRectangle(const MathUtil::Rectangle<int>& dst_rect, Texture2D* src_texture,
- const MathUtil::Rectangle<int>& src_rect);
+class VKStagingTexture final : public AbstractStagingTexture
+{
+public:
+ VKStagingTexture() = delete;
+ ~VKStagingTexture();
- std::optional<RawTextureInfo> MapFullImpl() override;
- std::optional<RawTextureInfo> MapRegionImpl(u32 level, u32 x, u32 y, u32 width,
- u32 height) override;
+ void CopyFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& src_rect,
+ u32 src_layer, u32 src_level,
+ const MathUtil::Rectangle<int>& dst_rect) override;
+ void CopyToTexture(const MathUtil::Rectangle<int>& src_rect, AbstractTexture* dst,
+ const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
+ u32 dst_level) override;
- std::unique_ptr<Texture2D> m_texture;
- std::unique_ptr<StagingTexture2D> m_staging_texture;
- VkFramebuffer m_framebuffer;
+ bool Map() override;
+ void Unmap() override;
+ void Flush() override;
+
+ // This overload is provided for compatibility as we dropped StagingTexture2D.
+ // For now, FramebufferManager relies on them. But we can drop it once we move that to common.
+ void CopyFromTexture(Texture2D* src, const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
+ u32 src_level, const MathUtil::Rectangle<int>& dst_rect);
+
+ static std::unique_ptr<VKStagingTexture> Create(StagingTextureType type,
+ const TextureConfig& config);
+
+private:
+ VKStagingTexture(StagingTextureType type, const TextureConfig& config,
+ std::unique_ptr<StagingBuffer> buffer);
+
+ std::unique_ptr<StagingBuffer> m_staging_buffer;
+ VkFence m_flush_fence = VK_NULL_HANDLE;
};
} // namespace Vulkan
diff --git a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj
index 3492f7b0f2..1a24ff053b 100644
--- a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj
+++ b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj
@@ -46,7 +46,6 @@
<ClCompile Include="PerfQuery.cpp" />
<ClCompile Include="RasterFont.cpp" />
<ClCompile Include="StagingBuffer.cpp" />
- <ClCompile Include="StagingTexture2D.cpp" />
<ClCompile Include="Util.cpp" />
<ClCompile Include="VertexFormat.cpp" />
<ClCompile Include="ObjectCache.cpp" />
@@ -72,7 +71,6 @@
<ClInclude Include="TextureConverter.h" />
<ClInclude Include="RasterFont.h" />
<ClInclude Include="StagingBuffer.h" />
- <ClInclude Include="StagingTexture2D.h" />
<ClInclude Include="Util.h" />
<ClInclude Include="VertexFormat.h" />
<ClInclude Include="PerfQuery.h" />