summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2016-11-20 00:08:24 +1000
committerStenzek <stenzek@gmail.com>2016-12-04 20:10:13 +1000
commitd67463e0a7570aeb00d2d10e21987fb639b78731 (patch)
treeace65edc48f07484a5d3045643cec95b1c6a7858 /Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
parentadd638538b24f5c7273323538ee4dab0f0271a16 (diff)
Vulkan: Simplify palette texture conversion
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/TextureConverter.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureConverter.cpp198
1 files changed, 96 insertions, 102 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
index 902d3d118c..690c0decf2 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
+++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
@@ -42,16 +42,16 @@ TextureConverter::~TextureConverter()
vkDestroyShaderModule(g_vulkan_context->GetDevice(), it, nullptr);
}
- if (m_palette_buffer_view != VK_NULL_HANDLE)
- vkDestroyBufferView(g_vulkan_context->GetDevice(), m_palette_buffer_view, nullptr);
+ if (m_texel_buffer_view_r16_uint != VK_NULL_HANDLE)
+ vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r16_uint, nullptr);
if (m_encoding_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr);
- if (m_encoding_texture_framebuffer != VK_NULL_HANDLE)
- vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_texture_framebuffer, nullptr);
+ if (m_encoding_render_framebuffer != VK_NULL_HANDLE)
+ vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr);
- for (VkShaderModule shader : m_texture_encoding_shaders)
+ for (VkShaderModule shader : m_encoding_shaders)
{
if (shader != VK_NULL_HANDLE)
vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr);
@@ -60,7 +60,7 @@ TextureConverter::~TextureConverter()
bool TextureConverter::Initialize()
{
- if (!CreateUniformBuffer())
+ if (!CreateTexelBuffer())
{
PanicAlert("Failed to create uniform buffer");
return false;
@@ -90,7 +90,7 @@ bool TextureConverter::Initialize()
return false;
}
- if (!CreateDownloadTexture())
+ if (!CreateEncodingDownloadTexture())
{
PanicAlert("Failed to create download texture");
return false;
@@ -99,10 +99,10 @@ bool TextureConverter::Initialize()
return true;
}
-void TextureConverter::ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass,
- VkFramebuffer dst_framebuffer, Texture2D* src_texture,
- u32 width, u32 height, void* palette, TlutFormat format,
- u32 src_format)
+void TextureConverter::ConvertTexture(TextureCache::TCacheEntry* dst_entry,
+ TextureCache::TCacheEntry* src_entry,
+ VkRenderPass render_pass, const void* palette,
+ TlutFormat palette_format)
{
struct PSUniformBlock
{
@@ -111,80 +111,65 @@ void TextureConverter::ConvertTexture(VkCommandBuffer command_buffer, VkRenderPa
int pad[2];
};
- _assert_(static_cast<size_t>(format) < NUM_PALETTE_CONVERSION_SHADERS);
+ _assert_(static_cast<size_t>(palette_format) < NUM_PALETTE_CONVERSION_SHADERS);
+ _assert_(dst_entry->config.rendertarget);
- size_t palette_size = (src_format & 0xF) == GX_TF_I4 ? 32 : 512;
- VkDescriptorSet texel_buffer_descriptor_set;
+ // We want to align to 2 bytes (R16) or the device's texel buffer alignment, whichever is greater.
+ VkDeviceSize texel_buffer_alignment =
+ std::min(g_vulkan_context->GetTexelBufferAlignment(), sizeof(u16));
+ size_t palette_size = (src_entry->format & 0xF) == GX_TF_I4 ? 32 : 512;
// Allocate memory for the palette, and descriptor sets for the buffer.
// If any of these fail, execute a command buffer, and try again.
- if (!m_palette_stream_buffer->ReserveMemory(palette_size,
- g_vulkan_context->GetTexelBufferAlignment()) ||
- (texel_buffer_descriptor_set = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS))) ==
- VK_NULL_HANDLE)
+ if (!m_texel_buffer->ReserveMemory(palette_size, texel_buffer_alignment))
{
WARN_LOG(VIDEO, "Executing command list while waiting for space in palette buffer");
Util::ExecuteCurrentCommandsAndRestoreState(false);
- if (!m_palette_stream_buffer->ReserveMemory(palette_size,
- g_vulkan_context->GetTexelBufferAlignment()) ||
- (texel_buffer_descriptor_set = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS))) ==
- VK_NULL_HANDLE)
+ if (!m_texel_buffer->ReserveMemory(palette_size, texel_buffer_alignment))
{
PanicAlert("Failed to allocate space for texture conversion");
return;
}
}
- // Fill descriptor set #2 (texel buffer)
- u32 palette_offset = static_cast<u32>(m_palette_stream_buffer->GetCurrentOffset());
- VkWriteDescriptorSet texel_set_write = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- nullptr,
- texel_buffer_descriptor_set,
- 0,
- 0,
- 1,
- VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
- nullptr,
- nullptr,
- &m_palette_buffer_view};
- vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), 1, &texel_set_write, 0, nullptr);
-
- Util::BufferMemoryBarrier(command_buffer, m_palette_stream_buffer->GetBuffer(),
- VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, palette_offset,
- palette_size, VK_PIPELINE_STAGE_HOST_BIT,
- VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
-
- // Set up draw
+ // Copy in palette to texel buffer.
+ u32 palette_offset = static_cast<u32>(m_texel_buffer->GetCurrentOffset());
+ memcpy(m_texel_buffer->GetCurrentHostPointer(), palette, palette_size);
+ m_texel_buffer->CommitMemory(palette_size);
+
+ // 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 (src_entry->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();
+ }
+
+ // Bind and draw to the destination.
UtilityShaderDraw draw(command_buffer,
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
render_pass, g_object_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
- m_palette_conversion_shaders[format]);
-
- VkRect2D region = {{0, 0}, {width, height}};
- draw.BeginRenderPass(dst_framebuffer, region);
+ m_palette_conversion_shaders[palette_format]);
- // Copy in palette
- memcpy(m_palette_stream_buffer->GetCurrentHostPointer(), palette, palette_size);
- m_palette_stream_buffer->CommitMemory(palette_size);
+ VkRect2D region = {{0, 0}, {dst_entry->config.width, dst_entry->config.height}};
+ draw.BeginRenderPass(dst_entry->GetFramebuffer(), region);
- // PS Uniforms/Samplers
PSUniformBlock uniforms = {};
- uniforms.multiplier = (src_format & 0xF) == GX_TF_I4 ? 15.0f : 255.0f;
+ uniforms.multiplier = (src_entry->format & 0xF) == GX_TF_I4 ? 15.0f : 255.0f;
uniforms.texel_buffer_offset = static_cast<int>(palette_offset / sizeof(u16));
draw.SetPushConstants(&uniforms, sizeof(uniforms));
- draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
-
- // We have to bind the texel buffer descriptor set separately.
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
- DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER, 1,
- &texel_buffer_descriptor_set, 0, nullptr);
-
- // Draw
- draw.SetViewportAndScissor(0, 0, width, height);
+ draw.SetPSSampler(0, src_entry->GetTexture()->GetView(), g_object_cache->GetPointSampler());
+ draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint);
+ draw.SetViewportAndScissor(0, 0, dst_entry->config.width, dst_entry->config.height);
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
draw.EndRenderPass();
}
@@ -195,7 +180,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
bool is_intensity, int scale_by_half,
const EFBRectangle& src_rect)
{
- if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE)
+ if (m_encoding_shaders[format] == VK_NULL_HANDLE)
{
ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format);
return;
@@ -207,7 +192,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(),
- VK_NULL_HANDLE, m_texture_encoding_shaders[format]);
+ VK_NULL_HANDLE, m_encoding_shaders[format]);
// Uniform - int4 of left,top,native_width,scale
s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast<s32>(native_width),
@@ -225,53 +210,65 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
render_height);
VkRect2D render_region = {{0, 0}, {render_width, render_height}};
- draw.BeginRenderPass(m_encoding_texture_framebuffer, render_region);
+ draw.BeginRenderPass(m_encoding_render_framebuffer, render_region);
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
draw.EndRenderPass();
// Transition the image before copying
- m_encoding_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
- m_download_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
- m_encoding_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
- render_width, render_height, 0, 0);
+ m_encoding_render_texture->OverrideImageLayout(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_download_texture->ReadTexels(0, 0, render_width, render_height, dest_ptr, memory_stride);
+ m_encoding_download_texture->ReadTexels(0, 0, render_width, render_height, dest_ptr,
+ memory_stride);
}
-bool TextureConverter::CreateUniformBuffer()
+bool TextureConverter::CreateTexelBuffer()
{
- // TODO: Check against maximum size
- static const size_t BUFFER_SIZE = 1024 * 1024;
-
- m_palette_stream_buffer =
- StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, BUFFER_SIZE, BUFFER_SIZE);
- if (!m_palette_stream_buffer)
+ // Prefer an 8MB buffer if possible, but use less if the device doesn't support this.
+ // This buffer is potentially going to be addressed as R8s in the future, so we assume
+ // that one element is one byte.
+ m_texel_buffer_size =
+ std::min(TEXTURE_CONVERSION_TEXEL_BUFFER_SIZE,
+ static_cast<size_t>(g_vulkan_context->GetDeviceLimits().maxTexelBufferElements));
+
+ m_texel_buffer = StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
+ m_texel_buffer_size, m_texel_buffer_size);
+ if (!m_texel_buffer)
return false;
+ // Create views of the formats that we will be using.
+ m_texel_buffer_view_r16_uint = CreateTexelBufferView(VK_FORMAT_R16_UINT);
+ return m_texel_buffer_view_r16_uint != VK_NULL_HANDLE;
+}
+
+VkBufferView TextureConverter::CreateTexelBufferView(VkFormat format) const
+{
// Create a view of the whole buffer, we'll offset our texel load into it
VkBufferViewCreateInfo view_info = {
VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType
nullptr, // const void* pNext
0, // VkBufferViewCreateFlags flags
- m_palette_stream_buffer->GetBuffer(), // VkBuffer buffer
- VK_FORMAT_R16_UINT, // VkFormat format
+ m_texel_buffer->GetBuffer(), // VkBuffer buffer
+ format, // VkFormat format
0, // VkDeviceSize offset
- BUFFER_SIZE // VkDeviceSize range
+ m_texel_buffer_size // VkDeviceSize range
};
- VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr,
- &m_palette_buffer_view);
+ VkBufferView view;
+ VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: ");
- return false;
+ return VK_NULL_HANDLE;
}
- return true;
+ return view;
}
bool TextureConverter::CompilePaletteConversionShaders()
@@ -283,8 +280,8 @@ bool TextureConverter::CompilePaletteConversionShaders()
int texture_buffer_offset;
} PC;
- layout(set = 1, binding = 0) uniform sampler2DArray samp0;
- layout(set = 0, binding = 0) uniform usamplerBuffer samp1;
+ SAMPLER_BINDING(0) uniform sampler2DArray samp0;
+ TEXEL_BUFFER_BINDING(0) uniform usamplerBuffer samp1;
layout(location = 0) in vec3 f_uv0;
layout(location = 0) out vec4 ocol0;
@@ -384,8 +381,8 @@ bool TextureConverter::CompileEncodingShaders()
{
const char* shader_source =
TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan);
- m_texture_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source);
- if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE)
+ m_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source);
+ if (m_encoding_shaders[format] == VK_NULL_HANDLE)
return false;
}
@@ -436,27 +433,27 @@ bool TextureConverter::CreateEncodingRenderPass()
bool TextureConverter::CreateEncodingTexture()
{
- m_encoding_texture = Texture2D::Create(
+ 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_texture)
+ if (!m_encoding_render_texture)
return false;
- VkImageView framebuffer_attachments[] = {m_encoding_texture->GetView()};
+ 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_texture->GetWidth(),
- m_encoding_texture->GetHeight(),
- m_encoding_texture->GetLayers()};
+ 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_texture_framebuffer);
+ &m_encoding_render_framebuffer);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
@@ -466,16 +463,13 @@ bool TextureConverter::CreateEncodingTexture()
return true;
}
-bool TextureConverter::CreateDownloadTexture()
+bool TextureConverter::CreateEncodingDownloadTexture()
{
- m_download_texture =
+ m_encoding_download_texture =
StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, ENCODING_TEXTURE_WIDTH,
ENCODING_TEXTURE_HEIGHT, ENCODING_TEXTURE_FORMAT);
- if (!m_download_texture || !m_download_texture->Map())
- return false;
-
- return true;
+ return m_encoding_download_texture && m_encoding_download_texture->Map();
}
} // namespace Vulkan