summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@users.noreply.github.com>2016-12-05 12:15:38 +1000
committerGitHub <noreply@github.com>2016-12-05 12:15:38 +1000
commit15e2133ce706fe8cd5613c81a8866abe03960e3b (patch)
tree56d578484881f78ec684f50804c7348f00bec1bb /Source/Core/VideoBackends/Vulkan/TextureCache.cpp
parentd1c89db8c809a89d5576dc9ea524629cfc4d29a6 (diff)
parent9736198c3b2552e51dd98445c0439dff759e08af (diff)
Merge pull request #4462 from stenzek/vulkan-faster-xfb
Vulkan: Cleanup/refactoring, faster RealXFB
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/TextureCache.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureCache.cpp371
1 files changed, 46 insertions, 325 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
index b607a91fd0..78892f9fb3 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
+++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp
@@ -17,13 +17,12 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/FramebufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
-#include "VideoBackends/Vulkan/PaletteTextureConverter.h"
#include "VideoBackends/Vulkan/Renderer.h"
#include "VideoBackends/Vulkan/StagingTexture2D.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/StreamBuffer.h"
#include "VideoBackends/Vulkan/Texture2D.h"
-#include "VideoBackends/Vulkan/TextureEncoder.h"
+#include "VideoBackends/Vulkan/TextureConverter.h"
#include "VideoBackends/Vulkan/Util.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
@@ -37,10 +36,8 @@ TextureCache::TextureCache()
TextureCache::~TextureCache()
{
- if (m_initialize_render_pass != VK_NULL_HANDLE)
- vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_initialize_render_pass, nullptr);
- if (m_update_render_pass != VK_NULL_HANDLE)
- vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_update_render_pass, nullptr);
+ if (m_render_pass != VK_NULL_HANDLE)
+ vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr);
TextureCache::DeleteShaders();
}
@@ -66,17 +63,10 @@ bool TextureCache::Initialize()
return false;
}
- m_texture_encoder = std::make_unique<TextureEncoder>();
- if (!m_texture_encoder->Initialize())
+ m_texture_converter = std::make_unique<TextureConverter>();
+ if (!m_texture_converter->Initialize())
{
- PanicAlert("Failed to initialize texture encoder.");
- return false;
- }
-
- m_palette_texture_converter = std::make_unique<PaletteTextureConverter>();
- if (!m_palette_texture_converter->Initialize())
- {
- PanicAlert("Failed to initialize palette texture converter");
+ PanicAlert("Failed to initialize texture converter");
return false;
}
@@ -94,31 +84,8 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
{
TCacheEntry* entry = static_cast<TCacheEntry*>(base_entry);
TCacheEntry* unconverted = static_cast<TCacheEntry*>(base_unconverted);
- _assert_(entry->config.rendertarget);
-
- // EFB copies can be used as paletted textures as well. For these, we can't assume them to be
- // contain the correct data before the frame begins (when the init command buffer is executed),
- // so we must convert them at the appropriate time, during the drawing command buffer.
- VkCommandBuffer command_buffer;
- if (unconverted->IsEfbCopy())
- {
- command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
- StateTracker::GetInstance()->EndRenderPass();
- StateTracker::GetInstance()->SetPendingRebind();
- }
- else
- {
- // Use initialization command buffer and perform conversion before the drawing commands.
- command_buffer = g_command_buffer_mgr->GetCurrentInitCommandBuffer();
- }
-
- m_palette_texture_converter->ConvertTexture(
- command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(),
- unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format,
- unconverted->format);
- // Render pass transitions to SHADER_READ_ONLY.
- entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ m_texture_converter->ConvertTexture(entry, unconverted, m_render_pass, palette, format);
}
static bool IsDepthCopyFormat(PEControl::PixelFormat format)
@@ -156,9 +123,9 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- m_texture_encoder->EncodeTextureToRam(src_texture->GetView(), dst, format, native_width,
- bytes_per_row, num_blocks_y, memory_stride, src_format,
- is_intensity, scale_by_half, src_rect);
+ m_texture_converter->EncodeTextureToMemory(src_texture->GetView(), dst, format, native_width,
+ bytes_per_row, num_blocks_y, memory_stride, src_format,
+ is_intensity, scale_by_half, src_rect);
// Transition back to original state
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout);
@@ -230,11 +197,10 @@ void TextureCache::ScaleTextureRectangle(TCacheEntry* dst_texture,
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
dst_texture->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- g_object_cache->GetStandardPipelineLayout(),
- GetRenderPassForTextureUpdate(dst_texture->GetTexture()),
+ g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), m_render_pass,
g_object_cache->GetPassthroughVertexShader(),
g_object_cache->GetPassthroughGeometryShader(), m_copy_shader);
@@ -248,9 +214,6 @@ void TextureCache::ScaleTextureRectangle(TCacheEntry* dst_texture,
static_cast<int>(src_texture->GetWidth()),
static_cast<int>(src_texture->GetHeight()));
draw.EndRenderPass();
-
- // Render pass transitions destination texture to SHADER_READ_ONLY.
- dst_texture->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config)
@@ -278,7 +241,7 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
- m_initialize_render_pass,
+ m_render_pass,
static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments,
texture->GetWidth(),
@@ -308,17 +271,6 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
bool TextureCache::CreateRenderPasses()
{
- static constexpr VkAttachmentDescription initialize_attachment = {
- 0,
- TEXTURECACHE_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_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
-
static constexpr VkAttachmentDescription update_attachment = {
0,
TEXTURECACHE_TEXTURE_FORMAT,
@@ -327,8 +279,8 @@ bool TextureCache::CreateRenderPasses()
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
static constexpr VkAttachmentReference color_attachment_reference = {
0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
@@ -340,36 +292,6 @@ bool TextureCache::CreateRenderPasses()
nullptr, nullptr,
0, nullptr};
- static constexpr VkSubpassDependency initialize_dependancies[] = {
- {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_DEPENDENCY_BY_REGION_BIT},
- {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_ACCESS_SHADER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
-
- static constexpr VkSubpassDependency update_dependancies[] = {
- {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_SHADER_READ_BIT,
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_DEPENDENCY_BY_REGION_BIT},
- {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_ACCESS_SHADER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
-
- VkRenderPassCreateInfo initialize_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- nullptr,
- 0,
- 1,
- &initialize_attachment,
- 1,
- &subpass_description,
- static_cast<u32>(ArraySize(initialize_dependancies)),
- initialize_dependancies};
-
VkRenderPassCreateInfo update_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
@@ -377,44 +299,20 @@ bool TextureCache::CreateRenderPasses()
&update_attachment,
1,
&subpass_description,
- static_cast<u32>(ArraySize(update_dependancies)),
- update_dependancies};
-
- VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &initialize_info, nullptr,
- &m_initialize_render_pass);
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkCreateRenderPass (initialize) failed: ");
- return false;
- }
+ 0,
+ nullptr};
- res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr,
- &m_update_render_pass);
+ VkResult res =
+ vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr, &m_render_pass);
if (res != VK_SUCCESS)
{
- LOG_VULKAN_ERROR(res, "vkCreateRenderPass (update) failed: ");
+ LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return false;
}
return true;
}
-VkRenderPass TextureCache::GetRenderPassForTextureUpdate(const Texture2D* texture) const
-{
- // EFB copies can be re-used as part of the texture pool. If this is the case, we need to insert
- // a pipeline barrier to ensure that all reads from the texture expecting the old data have
- // completed before overwriting the texture's contents. New textures will be in TRANSFER_DST
- // due to the clear after creation.
-
- // These two render passes are compatible, so even though the framebuffer was created with
- // the initialize render pass it's still allowed.
-
- if (texture->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
- return m_initialize_render_pass;
- else
- return m_update_render_pass;
-}
-
TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& config_,
std::unique_ptr<Texture2D> texture,
VkFramebuffer framebuffer)
@@ -437,27 +335,23 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
width = std::max(1u, std::min(width, m_texture->GetWidth() >> level));
height = std::max(1u, std::min(height, m_texture->GetHeight() >> level));
- // We don't care about the existing contents of the texture, so we set the image layout to
- // VK_IMAGE_LAYOUT_UNDEFINED here. However, if this texture is being re-used from the texture
- // pool, it may still be in use. We assume that it's not, as non-efb-copy textures are only
- // returned to the pool when the frame number is different, furthermore, we're doing this
- // on the initialize command buffer, so a texture being re-used mid-frame would have undesirable
- // effects regardless.
- VkImageMemoryBarrier 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_texture->GetImage(), // VkImage image
- {VK_IMAGE_ASPECT_COLOR_BIT, level, 1, 0, 1}, // VkImageSubresourceRange subresourceRange
- };
- vkCmdPipelineBarrier(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
- nullptr, 0, nullptr, 1, &barrier);
+ // We don't care about the existing contents of the texture, so we could the image layout to
+ // VK_IMAGE_LAYOUT_UNDEFINED here. However, under section 2.2.1, Queue Operation of the Vulkan
+ // specification, it states:
+ //
+ // Command buffer submissions to a single queue must always adhere to command order and
+ // API order, but otherwise may overlap or execute out of order.
+ //
+ // Therefore, if a previous frame's command buffer is still sampling from this texture, and we
+ // overwrite it without a pipeline barrier, a texture sample could occur in parallel with the
+ // texture upload/copy. I'm not sure if any drivers currently take advantage of this, but we
+ // should insert an explicit pipeline barrier just in case (done by TransitionToLayout).
+ //
+ // We transition to TRANSFER_DST, ready for the image copy, and leave the texture in this state.
+ // This is so that the remaining mip levels can be uploaded without barriers, and then when the
+ // texture is used, it can be transitioned to SHADER_READ_ONLY (see TCacheEntry::Bind).
+ m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Does this texture data fit within the streaming buffer?
u32 upload_width = width;
@@ -540,16 +434,6 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width,
height, level, 0);
}
-
- // Transition to shader read only.
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- vkCmdPipelineBarrier(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
- VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0,
- nullptr, 0, nullptr, 1, &barrier);
- m_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format,
@@ -586,11 +470,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
scale_by_half ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler();
VkImageLayout original_layout = src_texture->GetLayout();
src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
UtilityShaderDraw draw(
- command_buffer, g_object_cache->GetPushConstantPipelineLayout(),
- TextureCache::GetInstance()->GetRenderPassForTextureUpdate(m_texture.get()),
- g_object_cache->GetPassthroughVertexShader(), g_object_cache->GetPassthroughGeometryShader(),
+ command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
+ TextureCache::GetInstance()->m_render_pass, g_object_cache->GetPassthroughVertexShader(),
+ g_object_cache->GetPassthroughGeometryShader(),
is_depth_copy ? TextureCache::GetInstance()->m_efb_depth_to_tex_shader :
TextureCache::GetInstance()->m_efb_color_to_tex_shader);
@@ -614,7 +499,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
src_texture->TransitionToLayout(command_buffer, original_layout);
// Render pass transitions texture to SHADER_READ_ONLY.
- m_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source,
@@ -634,6 +519,8 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase*
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
+ m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView());
}
@@ -757,52 +644,6 @@ bool TextureCache::CompileShaders()
}
)";
- static const char RGB_TO_YUYV_SHADER_SOURCE[] = R"(
- SAMPLER_BINDING(0) uniform sampler2DArray source;
- layout(location = 0) in vec3 uv0;
- layout(location = 0) out vec4 ocol0;
-
- const vec3 y_const = vec3(0.257,0.504,0.098);
- const vec3 u_const = vec3(-0.148,-0.291,0.439);
- const vec3 v_const = vec3(0.439,-0.368,-0.071);
- const vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);
-
- void main()
- {
- vec3 c0 = texture(source, vec3(uv0.xy - dFdx(uv0.xy) * 0.25, 0.0)).rgb;
- vec3 c1 = texture(source, vec3(uv0.xy + dFdx(uv0.xy) * 0.25, 0.0)).rgb;
- vec3 c01 = (c0 + c1) * 0.5;
- ocol0 = vec4(dot(c1, y_const),
- dot(c01,u_const),
- dot(c0,y_const),
- dot(c01, v_const)) + const3;
- }
- )";
-
- static const char YUYV_TO_RGB_SHADER_SOURCE[] = R"(
- SAMPLER_BINDING(0) uniform sampler2D source;
- layout(location = 0) in vec3 uv0;
- layout(location = 0) out vec4 ocol0;
-
- void main()
- {
- ivec2 uv = ivec2(gl_FragCoord.xy);
- vec4 c0 = texelFetch(source, ivec2(uv.x / 2, uv.y), 0);
-
- // The texture used to stage the upload is in BGRA order.
- c0 = c0.zyxw;
-
- float y = mix(c0.r, c0.b, (uv.x & 1) == 1);
- float yComp = 1.164 * (y - 0.0625);
- float uComp = c0.g - 0.5;
- float vComp = c0.a - 0.5;
- ocol0 = vec4(yComp + (1.596 * vComp),
- yComp - (0.813 * vComp) - (0.391 * uComp),
- yComp + (2.018 * uComp),
- 1.0);
- }
- )";
-
std::string header = g_object_cache->GetUtilityShaderHeader();
std::string source;
@@ -818,14 +659,8 @@ bool TextureCache::CompileShaders()
source = header + EFB_DEPTH_TO_TEX_SOURCE;
m_efb_depth_to_tex_shader = Util::CompileAndCreateFragmentShader(source);
- source = header + RGB_TO_YUYV_SHADER_SOURCE;
- m_rgb_to_yuyv_shader = Util::CompileAndCreateFragmentShader(source);
- source = header + YUYV_TO_RGB_SHADER_SOURCE;
- m_yuyv_to_rgb_shader = Util::CompileAndCreateFragmentShader(source);
-
- return (m_copy_shader != VK_NULL_HANDLE && m_efb_color_to_tex_shader != VK_NULL_HANDLE &&
- m_efb_depth_to_tex_shader != VK_NULL_HANDLE && m_rgb_to_yuyv_shader != VK_NULL_HANDLE &&
- m_yuyv_to_rgb_shader != VK_NULL_HANDLE);
+ return m_copy_shader != VK_NULL_HANDLE && m_efb_color_to_tex_shader != VK_NULL_HANDLE &&
+ m_efb_depth_to_tex_shader != VK_NULL_HANDLE;
}
void TextureCache::DeleteShaders()
@@ -849,120 +684,6 @@ void TextureCache::DeleteShaders()
vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_efb_depth_to_tex_shader, nullptr);
m_efb_depth_to_tex_shader = VK_NULL_HANDLE;
}
- if (m_rgb_to_yuyv_shader != VK_NULL_HANDLE)
- {
- vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_rgb_to_yuyv_shader, nullptr);
- m_rgb_to_yuyv_shader = VK_NULL_HANDLE;
- }
- if (m_yuyv_to_rgb_shader != VK_NULL_HANDLE)
- {
- vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_yuyv_to_rgb_shader, nullptr);
- m_yuyv_to_rgb_shader = VK_NULL_HANDLE;
- }
-}
-
-void TextureCache::EncodeYUYVTextureToMemory(void* dst_ptr, u32 dst_width, u32 dst_stride,
- u32 dst_height, Texture2D* src_texture,
- const MathUtil::Rectangle<int>& src_rect)
-{
- StateTracker::GetInstance()->EndRenderPass();
-
- VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
- src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-
- // Borrow framebuffer from EFB2RAM encoder.
- Texture2D* encoding_texture = m_texture_encoder->GetEncodingTexture();
- StagingTexture2D* download_texture = m_texture_encoder->GetDownloadTexture();
- encoding_texture->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
- // the order the guest is expecting and we don't have to swap it at readback time. The width
- // is halved because we're using an RGBA8 texture, but the YUYV data is two bytes per pixel.
- u32 output_width = dst_width / 2;
- UtilityShaderDraw draw(command_buffer, g_object_cache->GetStandardPipelineLayout(),
- m_texture_encoder->GetEncodingRenderPass(),
- g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE,
- m_rgb_to_yuyv_shader);
- VkRect2D region = {{0, 0}, {output_width, dst_height}};
- draw.BeginRenderPass(m_texture_encoder->GetEncodingTextureFramebuffer(), 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(),
- static_cast<int>(src_texture->GetWidth()),
- static_cast<int>(src_texture->GetHeight()));
- draw.EndRenderPass();
-
- // Render pass transitions to TRANSFER_SRC.
- encoding_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
-
- // Copy from encoding texture to download buffer.
- download_texture->CopyFromImage(command_buffer, encoding_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.
- download_texture->ReadTexels(0, 0, output_width, dst_height, dst_ptr, dst_stride);
-}
-
-void TextureCache::DecodeYUYVTextureFromMemory(TCacheEntry* dst_texture, const void* src_ptr,
- u32 src_width, u32 src_stride, u32 src_height)
-{
- // Copies (and our decoding step) cannot be done inside a render pass.
- StateTracker::GetInstance()->EndRenderPass();
-
- // We share the upload buffer with normal textures here, since the XFB buffers aren't very large.
- u32 upload_size = src_stride * src_height;
- if (!m_texture_upload_buffer->ReserveMemory(upload_size,
- g_vulkan_context->GetBufferImageGranularity()))
- {
- // Execute the command buffer first.
- WARN_LOG(VIDEO, "Executing command list while waiting for space in texture upload buffer");
- Util::ExecuteCurrentCommandsAndRestoreState(false);
- if (!m_texture_upload_buffer->ReserveMemory(upload_size,
- g_vulkan_context->GetBufferImageGranularity()))
- PanicAlert("Failed to allocate space in texture upload buffer");
- }
-
- // Assume that each source row is not padded.
- _assert_(src_stride == (src_width * sizeof(u16)));
- VkDeviceSize image_upload_buffer_offset = m_texture_upload_buffer->GetCurrentOffset();
- std::memcpy(m_texture_upload_buffer->GetCurrentHostPointer(), src_ptr, upload_size);
- m_texture_upload_buffer->CommitMemory(upload_size);
-
- // Copy from the upload buffer to the intermediate texture. We borrow this from the encoder.
- // The width is specified as half here because we have two pixels packed in each RGBA texel.
- // In the future this could be skipped by reading the upload buffer as a uniform texel buffer.
- VkBufferImageCopy image_copy = {
- image_upload_buffer_offset, // VkDeviceSize bufferOffset
- 0, // uint32_t bufferRowLength
- 0, // uint32_t bufferImageHeight
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, // VkImageSubresourceLayers imageSubresource
- {0, 0, 0}, // VkOffset3D imageOffset
- {src_width / 2, src_height, 1} // VkExtent3D imageExtent
- };
- VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
- Texture2D* intermediate_texture = m_texture_encoder->GetEncodingTexture();
- intermediate_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
- vkCmdCopyBufferToImage(command_buffer, m_texture_upload_buffer->GetBuffer(),
- intermediate_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
- &image_copy);
- intermediate_texture->TransitionToLayout(command_buffer,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- dst_texture->GetTexture()->TransitionToLayout(command_buffer,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
- // Convert from the YUYV data now in the intermediate texture to RGBA in the destination.
- UtilityShaderDraw draw(command_buffer, g_object_cache->GetStandardPipelineLayout(),
- m_texture_encoder->GetEncodingRenderPass(),
- g_object_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
- m_yuyv_to_rgb_shader);
- VkRect2D region = {{0, 0}, {src_width, src_height}};
- draw.BeginRenderPass(dst_texture->GetFramebuffer(), region);
- draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height));
- draw.SetPSSampler(0, intermediate_texture->GetView(), g_object_cache->GetPointSampler());
- draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
- draw.EndRenderPass();
}
} // namespace Vulkan