Vulkan: Simplify palette texture conversion
This commit is contained in:
parent
add638538b
commit
d67463e0a7
|
@ -107,6 +107,9 @@ constexpr size_t STAGING_TEXTURE_UPLOAD_THRESHOLD = 1024 * 1024 * 4;
|
||||||
constexpr size_t INITIAL_UNIFORM_STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
|
constexpr size_t INITIAL_UNIFORM_STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
|
||||||
constexpr size_t MAXIMUM_UNIFORM_STREAM_BUFFER_SIZE = 32 * 1024 * 1024;
|
constexpr size_t MAXIMUM_UNIFORM_STREAM_BUFFER_SIZE = 32 * 1024 * 1024;
|
||||||
|
|
||||||
|
// Texel buffer size for palette and texture decoding.
|
||||||
|
constexpr size_t TEXTURE_CONVERSION_TEXEL_BUFFER_SIZE = 8 * 1024 * 1024;
|
||||||
|
|
||||||
// Push constant buffer size for utility shaders
|
// Push constant buffer size for utility shaders
|
||||||
constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
|
constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
|
||||||
|
|
||||||
|
|
|
@ -86,28 +86,9 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
|
||||||
{
|
{
|
||||||
TCacheEntry* entry = static_cast<TCacheEntry*>(base_entry);
|
TCacheEntry* entry = static_cast<TCacheEntry*>(base_entry);
|
||||||
TCacheEntry* unconverted = static_cast<TCacheEntry*>(base_unconverted);
|
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_texture_converter->ConvertTexture(
|
m_texture_converter->ConvertTexture(
|
||||||
command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(),
|
entry, unconverted, GetRenderPassForTextureUpdate(entry->GetTexture()), palette, format);
|
||||||
unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format,
|
|
||||||
unconverted->format);
|
|
||||||
|
|
||||||
// Render pass transitions to SHADER_READ_ONLY.
|
// Render pass transitions to SHADER_READ_ONLY.
|
||||||
entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
|
@ -42,16 +42,16 @@ TextureConverter::~TextureConverter()
|
||||||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), it, nullptr);
|
vkDestroyShaderModule(g_vulkan_context->GetDevice(), it, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_palette_buffer_view != VK_NULL_HANDLE)
|
if (m_texel_buffer_view_r16_uint != VK_NULL_HANDLE)
|
||||||
vkDestroyBufferView(g_vulkan_context->GetDevice(), m_palette_buffer_view, nullptr);
|
vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r16_uint, nullptr);
|
||||||
|
|
||||||
if (m_encoding_render_pass != VK_NULL_HANDLE)
|
if (m_encoding_render_pass != VK_NULL_HANDLE)
|
||||||
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr);
|
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr);
|
||||||
|
|
||||||
if (m_encoding_texture_framebuffer != VK_NULL_HANDLE)
|
if (m_encoding_render_framebuffer != VK_NULL_HANDLE)
|
||||||
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_texture_framebuffer, nullptr);
|
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)
|
if (shader != VK_NULL_HANDLE)
|
||||||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr);
|
vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr);
|
||||||
|
@ -60,7 +60,7 @@ TextureConverter::~TextureConverter()
|
||||||
|
|
||||||
bool TextureConverter::Initialize()
|
bool TextureConverter::Initialize()
|
||||||
{
|
{
|
||||||
if (!CreateUniformBuffer())
|
if (!CreateTexelBuffer())
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to create uniform buffer");
|
PanicAlert("Failed to create uniform buffer");
|
||||||
return false;
|
return false;
|
||||||
|
@ -90,7 +90,7 @@ bool TextureConverter::Initialize()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateDownloadTexture())
|
if (!CreateEncodingDownloadTexture())
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to create download texture");
|
PanicAlert("Failed to create download texture");
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,10 +99,10 @@ bool TextureConverter::Initialize()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureConverter::ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass,
|
void TextureConverter::ConvertTexture(TextureCache::TCacheEntry* dst_entry,
|
||||||
VkFramebuffer dst_framebuffer, Texture2D* src_texture,
|
TextureCache::TCacheEntry* src_entry,
|
||||||
u32 width, u32 height, void* palette, TlutFormat format,
|
VkRenderPass render_pass, const void* palette,
|
||||||
u32 src_format)
|
TlutFormat palette_format)
|
||||||
{
|
{
|
||||||
struct PSUniformBlock
|
struct PSUniformBlock
|
||||||
{
|
{
|
||||||
|
@ -111,80 +111,65 @@ void TextureConverter::ConvertTexture(VkCommandBuffer command_buffer, VkRenderPa
|
||||||
int pad[2];
|
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;
|
// We want to align to 2 bytes (R16) or the device's texel buffer alignment, whichever is greater.
|
||||||
VkDescriptorSet texel_buffer_descriptor_set;
|
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.
|
// Allocate memory for the palette, and descriptor sets for the buffer.
|
||||||
// If any of these fail, execute a command buffer, and try again.
|
// If any of these fail, execute a command buffer, and try again.
|
||||||
if (!m_palette_stream_buffer->ReserveMemory(palette_size,
|
if (!m_texel_buffer->ReserveMemory(palette_size, texel_buffer_alignment))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
WARN_LOG(VIDEO, "Executing command list while waiting for space in palette buffer");
|
WARN_LOG(VIDEO, "Executing command list while waiting for space in palette buffer");
|
||||||
Util::ExecuteCurrentCommandsAndRestoreState(false);
|
Util::ExecuteCurrentCommandsAndRestoreState(false);
|
||||||
|
|
||||||
if (!m_palette_stream_buffer->ReserveMemory(palette_size,
|
if (!m_texel_buffer->ReserveMemory(palette_size, texel_buffer_alignment))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to allocate space for texture conversion");
|
PanicAlert("Failed to allocate space for texture conversion");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill descriptor set #2 (texel buffer)
|
// Copy in palette to texel buffer.
|
||||||
u32 palette_offset = static_cast<u32>(m_palette_stream_buffer->GetCurrentOffset());
|
u32 palette_offset = static_cast<u32>(m_texel_buffer->GetCurrentOffset());
|
||||||
VkWriteDescriptorSet texel_set_write = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
memcpy(m_texel_buffer->GetCurrentHostPointer(), palette, palette_size);
|
||||||
nullptr,
|
m_texel_buffer->CommitMemory(palette_size);
|
||||||
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(),
|
// EFB copies can be used as paletted textures as well. For these, we can't assume them to be
|
||||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, palette_offset,
|
// contain the correct data before the frame begins (when the init command buffer is executed),
|
||||||
palette_size, VK_PIPELINE_STAGE_HOST_BIT,
|
// so we must convert them at the appropriate time, during the drawing command buffer.
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
// Set up draw
|
// Bind and draw to the destination.
|
||||||
UtilityShaderDraw draw(command_buffer,
|
UtilityShaderDraw draw(command_buffer,
|
||||||
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
|
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
|
||||||
render_pass, g_object_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
|
render_pass, g_object_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
|
||||||
m_palette_conversion_shaders[format]);
|
m_palette_conversion_shaders[palette_format]);
|
||||||
|
|
||||||
VkRect2D region = {{0, 0}, {width, height}};
|
VkRect2D region = {{0, 0}, {dst_entry->config.width, dst_entry->config.height}};
|
||||||
draw.BeginRenderPass(dst_framebuffer, region);
|
draw.BeginRenderPass(dst_entry->GetFramebuffer(), region);
|
||||||
|
|
||||||
// Copy in palette
|
|
||||||
memcpy(m_palette_stream_buffer->GetCurrentHostPointer(), palette, palette_size);
|
|
||||||
m_palette_stream_buffer->CommitMemory(palette_size);
|
|
||||||
|
|
||||||
// PS Uniforms/Samplers
|
|
||||||
PSUniformBlock uniforms = {};
|
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));
|
uniforms.texel_buffer_offset = static_cast<int>(palette_offset / sizeof(u16));
|
||||||
draw.SetPushConstants(&uniforms, sizeof(uniforms));
|
draw.SetPushConstants(&uniforms, sizeof(uniforms));
|
||||||
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
draw.SetPSSampler(0, src_entry->GetTexture()->GetView(), g_object_cache->GetPointSampler());
|
||||||
|
draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint);
|
||||||
// We have to bind the texel buffer descriptor set separately.
|
draw.SetViewportAndScissor(0, 0, dst_entry->config.width, dst_entry->config.height);
|
||||||
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.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
}
|
}
|
||||||
|
@ -195,7 +180,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
|
||||||
bool is_intensity, int scale_by_half,
|
bool is_intensity, int scale_by_half,
|
||||||
const EFBRectangle& src_rect)
|
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);
|
ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format);
|
||||||
return;
|
return;
|
||||||
|
@ -207,7 +192,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
|
||||||
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
|
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
|
||||||
m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(),
|
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
|
// Uniform - int4 of left,top,native_width,scale
|
||||||
s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast<s32>(native_width),
|
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);
|
render_height);
|
||||||
|
|
||||||
VkRect2D render_region = {{0, 0}, {render_width, 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.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Transition the image before copying
|
// Transition the image before copying
|
||||||
m_encoding_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
m_encoding_render_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
m_download_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_encoding_download_texture->CopyFromImage(
|
||||||
m_encoding_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
|
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_encoding_render_texture->GetImage(),
|
||||||
render_width, render_height, 0, 0);
|
VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, render_width, render_height, 0, 0);
|
||||||
|
|
||||||
// Block until the GPU has finished copying to the staging texture.
|
// Block until the GPU has finished copying to the staging texture.
|
||||||
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
||||||
|
|
||||||
// Copy from staging texture to the final destination, adjusting pitch if necessary.
|
// 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
|
// Prefer an 8MB buffer if possible, but use less if the device doesn't support this.
|
||||||
static const size_t BUFFER_SIZE = 1024 * 1024;
|
// 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_palette_stream_buffer =
|
m_texel_buffer = StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
|
||||||
StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, BUFFER_SIZE, BUFFER_SIZE);
|
m_texel_buffer_size, m_texel_buffer_size);
|
||||||
if (!m_palette_stream_buffer)
|
if (!m_texel_buffer)
|
||||||
return false;
|
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
|
// Create a view of the whole buffer, we'll offset our texel load into it
|
||||||
VkBufferViewCreateInfo view_info = {
|
VkBufferViewCreateInfo view_info = {
|
||||||
VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkBufferViewCreateFlags flags
|
0, // VkBufferViewCreateFlags flags
|
||||||
m_palette_stream_buffer->GetBuffer(), // VkBuffer buffer
|
m_texel_buffer->GetBuffer(), // VkBuffer buffer
|
||||||
VK_FORMAT_R16_UINT, // VkFormat format
|
format, // VkFormat format
|
||||||
0, // VkDeviceSize offset
|
0, // VkDeviceSize offset
|
||||||
BUFFER_SIZE // VkDeviceSize range
|
m_texel_buffer_size // VkDeviceSize range
|
||||||
};
|
};
|
||||||
|
|
||||||
VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr,
|
VkBufferView view;
|
||||||
&m_palette_buffer_view);
|
VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: ");
|
LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: ");
|
||||||
return false;
|
return VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureConverter::CompilePaletteConversionShaders()
|
bool TextureConverter::CompilePaletteConversionShaders()
|
||||||
|
@ -283,8 +280,8 @@ bool TextureConverter::CompilePaletteConversionShaders()
|
||||||
int texture_buffer_offset;
|
int texture_buffer_offset;
|
||||||
} PC;
|
} PC;
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform sampler2DArray samp0;
|
SAMPLER_BINDING(0) uniform sampler2DArray samp0;
|
||||||
layout(set = 0, binding = 0) uniform usamplerBuffer samp1;
|
TEXEL_BUFFER_BINDING(0) uniform usamplerBuffer samp1;
|
||||||
|
|
||||||
layout(location = 0) in vec3 f_uv0;
|
layout(location = 0) in vec3 f_uv0;
|
||||||
layout(location = 0) out vec4 ocol0;
|
layout(location = 0) out vec4 ocol0;
|
||||||
|
@ -384,8 +381,8 @@ bool TextureConverter::CompileEncodingShaders()
|
||||||
{
|
{
|
||||||
const char* shader_source =
|
const char* shader_source =
|
||||||
TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan);
|
TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan);
|
||||||
m_texture_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source);
|
m_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source);
|
||||||
if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE)
|
if (m_encoding_shaders[format] == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,27 +433,27 @@ bool TextureConverter::CreateEncodingRenderPass()
|
||||||
|
|
||||||
bool TextureConverter::CreateEncodingTexture()
|
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,
|
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_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_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||||
if (!m_encoding_texture)
|
if (!m_encoding_render_texture)
|
||||||
return false;
|
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,
|
VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
nullptr,
|
nullptr,
|
||||||
0,
|
0,
|
||||||
m_encoding_render_pass,
|
m_encoding_render_pass,
|
||||||
static_cast<u32>(ArraySize(framebuffer_attachments)),
|
static_cast<u32>(ArraySize(framebuffer_attachments)),
|
||||||
framebuffer_attachments,
|
framebuffer_attachments,
|
||||||
m_encoding_texture->GetWidth(),
|
m_encoding_render_texture->GetWidth(),
|
||||||
m_encoding_texture->GetHeight(),
|
m_encoding_render_texture->GetHeight(),
|
||||||
m_encoding_texture->GetLayers()};
|
m_encoding_render_texture->GetLayers()};
|
||||||
|
|
||||||
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
||||||
&m_encoding_texture_framebuffer);
|
&m_encoding_render_framebuffer);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
|
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
|
||||||
|
@ -466,16 +463,13 @@ bool TextureConverter::CreateEncodingTexture()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureConverter::CreateDownloadTexture()
|
bool TextureConverter::CreateEncodingDownloadTexture()
|
||||||
{
|
{
|
||||||
m_download_texture =
|
m_encoding_download_texture =
|
||||||
StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, ENCODING_TEXTURE_WIDTH,
|
StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, ENCODING_TEXTURE_WIDTH,
|
||||||
ENCODING_TEXTURE_HEIGHT, ENCODING_TEXTURE_FORMAT);
|
ENCODING_TEXTURE_HEIGHT, ENCODING_TEXTURE_FORMAT);
|
||||||
|
|
||||||
if (!m_download_texture || !m_download_texture->Map())
|
return m_encoding_download_texture && m_encoding_download_texture->Map();
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||||
|
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||||
#include "VideoCommon/BPMemory.h"
|
#include "VideoCommon/BPMemory.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
@ -25,14 +26,14 @@ public:
|
||||||
~TextureConverter();
|
~TextureConverter();
|
||||||
|
|
||||||
VkRenderPass GetEncodingRenderPass() const { return m_encoding_render_pass; }
|
VkRenderPass GetEncodingRenderPass() const { return m_encoding_render_pass; }
|
||||||
Texture2D* GetEncodingTexture() const { return m_encoding_texture.get(); }
|
Texture2D* GetEncodingTexture() const { return m_encoding_render_texture.get(); }
|
||||||
VkFramebuffer GetEncodingTextureFramebuffer() const { return m_encoding_texture_framebuffer; }
|
VkFramebuffer GetEncodingTextureFramebuffer() const { return m_encoding_render_framebuffer; }
|
||||||
StagingTexture2D* GetDownloadTexture() const { return m_download_texture.get(); }
|
StagingTexture2D* GetDownloadTexture() const { return m_encoding_download_texture.get(); }
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
void ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass,
|
// Applies palette to dst_entry, using indices from src_entry.
|
||||||
VkFramebuffer dst_framebuffer, Texture2D* src_texture, u32 width, u32 height,
|
void ConvertTexture(TextureCache::TCacheEntry* dst_entry, TextureCache::TCacheEntry* src_entry,
|
||||||
void* palette, TlutFormat format, u32 src_format);
|
VkRenderPass render_pass, const void* palette, TlutFormat palette_format);
|
||||||
|
|
||||||
// Uses an encoding shader to copy src_texture to dest_ptr.
|
// Uses an encoding shader to copy src_texture to dest_ptr.
|
||||||
// NOTE: Executes the current command buffer.
|
// NOTE: Executes the current command buffer.
|
||||||
|
@ -48,28 +49,30 @@ private:
|
||||||
static const VkFormat ENCODING_TEXTURE_FORMAT = VK_FORMAT_B8G8R8A8_UNORM;
|
static const VkFormat ENCODING_TEXTURE_FORMAT = VK_FORMAT_B8G8R8A8_UNORM;
|
||||||
static const size_t NUM_PALETTE_CONVERSION_SHADERS = 3;
|
static const size_t NUM_PALETTE_CONVERSION_SHADERS = 3;
|
||||||
|
|
||||||
bool CreateUniformBuffer();
|
bool CreateTexelBuffer();
|
||||||
|
VkBufferView CreateTexelBufferView(VkFormat format) const;
|
||||||
|
|
||||||
bool CompilePaletteConversionShaders();
|
bool CompilePaletteConversionShaders();
|
||||||
|
|
||||||
bool CompileEncodingShaders();
|
bool CompileEncodingShaders();
|
||||||
bool CreateEncodingRenderPass();
|
bool CreateEncodingRenderPass();
|
||||||
bool CreateEncodingTexture();
|
bool CreateEncodingTexture();
|
||||||
bool CreateDownloadTexture();
|
bool CreateEncodingDownloadTexture();
|
||||||
|
|
||||||
|
// Shared between conversion types
|
||||||
|
std::unique_ptr<StreamBuffer> m_texel_buffer;
|
||||||
|
VkBufferView m_texel_buffer_view_r16_uint = VK_NULL_HANDLE;
|
||||||
|
size_t m_texel_buffer_size = 0;
|
||||||
|
|
||||||
|
// Palette conversion - taking an indexed texture and applying palette
|
||||||
std::array<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_shaders = {};
|
std::array<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_shaders = {};
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> m_palette_stream_buffer;
|
// Texture encoding - RGBA8->GX format in memory
|
||||||
VkBufferView m_palette_buffer_view = VK_NULL_HANDLE;
|
std::array<VkShaderModule, NUM_TEXTURE_ENCODING_SHADERS> m_encoding_shaders = {};
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> m_uniform_buffer;
|
|
||||||
|
|
||||||
std::array<VkShaderModule, NUM_TEXTURE_ENCODING_SHADERS> m_texture_encoding_shaders = {};
|
|
||||||
|
|
||||||
VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE;
|
||||||
|
std::unique_ptr<Texture2D> m_encoding_render_texture;
|
||||||
std::unique_ptr<Texture2D> m_encoding_texture;
|
VkFramebuffer m_encoding_render_framebuffer = VK_NULL_HANDLE;
|
||||||
VkFramebuffer m_encoding_texture_framebuffer = VK_NULL_HANDLE;
|
std::unique_ptr<StagingTexture2D> m_encoding_download_texture;
|
||||||
|
|
||||||
std::unique_ptr<StagingTexture2D> m_download_texture;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
Loading…
Reference in New Issue