diff --git a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt index 82d471ba54..fc5ac99df9 100644 --- a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt +++ b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt @@ -3,7 +3,6 @@ set(SRCS CommandBufferManager.cpp FramebufferManager.cpp ObjectCache.cpp - PaletteTextureConverter.cpp PerfQuery.cpp RasterFont.cpp Renderer.cpp @@ -15,11 +14,11 @@ set(SRCS SwapChain.cpp Texture2D.cpp TextureCache.cpp - TextureEncoder.cpp + TextureConverter.cpp Util.cpp VertexFormat.cpp VertexManager.cpp - VulkanContext.cpp + VulkanContext.cpp VulkanLoader.cpp main.cpp ) diff --git a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp deleted file mode 100644 index 7db6286805..0000000000 --- a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/Vulkan/PaletteTextureConverter.h" - -#include -#include -#include -#include - -#include "Common/Assert.h" -#include "Common/CommonFuncs.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" - -#include "VideoBackends/Vulkan/CommandBufferManager.h" -#include "VideoBackends/Vulkan/FramebufferManager.h" -#include "VideoBackends/Vulkan/ObjectCache.h" -#include "VideoBackends/Vulkan/Renderer.h" -#include "VideoBackends/Vulkan/StateTracker.h" -#include "VideoBackends/Vulkan/StreamBuffer.h" -#include "VideoBackends/Vulkan/Texture2D.h" -#include "VideoBackends/Vulkan/Util.h" -#include "VideoBackends/Vulkan/VulkanContext.h" - -namespace Vulkan -{ -PaletteTextureConverter::PaletteTextureConverter() -{ -} - -PaletteTextureConverter::~PaletteTextureConverter() -{ - for (const auto& it : m_shaders) - { - if (it != VK_NULL_HANDLE) - 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); -} - -bool PaletteTextureConverter::Initialize() -{ - if (!CreateBuffers()) - return false; - - if (!CompileShaders()) - return false; - - return true; -} - -void PaletteTextureConverter::ConvertTexture(VkCommandBuffer command_buffer, - VkRenderPass render_pass, - VkFramebuffer dst_framebuffer, Texture2D* src_texture, - u32 width, u32 height, void* palette, - TlutFormat format, u32 src_format) -{ - struct PSUniformBlock - { - float multiplier; - int texel_buffer_offset; - int pad[2]; - }; - - _assert_(static_cast(format) < NUM_PALETTE_CONVERSION_SHADERS); - - size_t palette_size = (src_format & 0xF) == GX_TF_I4 ? 32 : 512; - VkDescriptorSet texel_buffer_descriptor_set; - - // 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) - { - 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) - { - PanicAlert("Failed to allocate space for texture conversion"); - return; - } - } - - // Fill descriptor set #2 (texel buffer) - u32 palette_offset = static_cast(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 - UtilityShaderDraw draw( - command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION), - render_pass, g_object_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE, m_shaders[format]); - - VkRect2D region = {{0, 0}, {width, height}}; - draw.BeginRenderPass(dst_framebuffer, 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 = {}; - uniforms.multiplier = (src_format & 0xF) == GX_TF_I4 ? 15.0f : 255.0f; - uniforms.texel_buffer_offset = static_cast(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.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); - draw.EndRenderPass(); -} - -bool PaletteTextureConverter::CreateBuffers() -{ - // 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) - return false; - - // 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 - 0, // VkDeviceSize offset - BUFFER_SIZE // VkDeviceSize range - }; - - VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr, - &m_palette_buffer_view); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: "); - return false; - } - - return true; -} - -bool PaletteTextureConverter::CompileShaders() -{ - static const char PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE[] = R"( - layout(std140, push_constant) uniform PCBlock - { - float multiplier; - int texture_buffer_offset; - } PC; - - layout(set = 1, binding = 0) uniform sampler2DArray samp0; - layout(set = 0, binding = 0) uniform usamplerBuffer samp1; - - layout(location = 0) in vec3 f_uv0; - layout(location = 0) out vec4 ocol0; - - int Convert3To8(int v) - { - // Swizzle bits: 00000123 -> 12312312 - return (v << 5) | (v << 2) | (v >> 1); - } - int Convert4To8(int v) - { - // Swizzle bits: 00001234 -> 12341234 - return (v << 4) | v; - } - int Convert5To8(int v) - { - // Swizzle bits: 00012345 -> 12345123 - return (v << 3) | (v >> 2); - } - int Convert6To8(int v) - { - // Swizzle bits: 00123456 -> 12345612 - return (v << 2) | (v >> 4); - } - float4 DecodePixel_RGB5A3(int val) - { - int r,g,b,a; - if ((val&0x8000) > 0) - { - r=Convert5To8((val>>10) & 0x1f); - g=Convert5To8((val>>5 ) & 0x1f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - } - else - { - a=Convert3To8((val>>12) & 0x7); - r=Convert4To8((val>>8 ) & 0xf); - g=Convert4To8((val>>4 ) & 0xf); - b=Convert4To8((val ) & 0xf); - } - return float4(r, g, b, a) / 255.0; - } - float4 DecodePixel_RGB565(int val) - { - int r, g, b, a; - r = Convert5To8((val >> 11) & 0x1f); - g = Convert6To8((val >> 5) & 0x3f); - b = Convert5To8((val) & 0x1f); - a = 0xFF; - return float4(r, g, b, a) / 255.0; - } - float4 DecodePixel_IA8(int val) - { - int i = val & 0xFF; - int a = val >> 8; - return float4(i, i, i, a) / 255.0; - } - void main() - { - int src = int(round(texture(samp0, f_uv0).r * PC.multiplier)); - src = int(texelFetch(samp1, src + PC.texture_buffer_offset).r); - src = ((src << 8) & 0xFF00) | (src >> 8); - ocol0 = DECODE(src); - } - - )"; - - std::string palette_ia8_program = StringFromFormat("%s\n%s", "#define DECODE DecodePixel_IA8", - PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); - std::string palette_rgb565_program = StringFromFormat( - "%s\n%s", "#define DECODE DecodePixel_RGB565", PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); - std::string palette_rgb5a3_program = StringFromFormat( - "%s\n%s", "#define DECODE DecodePixel_RGB5A3", PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); - - m_shaders[GX_TL_IA8] = Util::CompileAndCreateFragmentShader(palette_ia8_program); - m_shaders[GX_TL_RGB565] = Util::CompileAndCreateFragmentShader(palette_rgb565_program); - m_shaders[GX_TL_RGB5A3] = Util::CompileAndCreateFragmentShader(palette_rgb5a3_program); - - return (m_shaders[GX_TL_IA8] != VK_NULL_HANDLE && m_shaders[GX_TL_RGB565] != VK_NULL_HANDLE && - m_shaders[GX_TL_RGB5A3] != VK_NULL_HANDLE); -} - -} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h deleted file mode 100644 index 668e35eae6..0000000000 --- a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "Common/CommonTypes.h" -#include "VideoBackends/Vulkan/StreamBuffer.h" -#include "VideoCommon/TextureDecoder.h" - -namespace Vulkan -{ -class Texture2D; - -// Since this converter uses a uniform texel buffer, we can't use the general pipeline generators. - -class PaletteTextureConverter -{ -public: - PaletteTextureConverter(); - ~PaletteTextureConverter(); - - bool Initialize(); - - void ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass, - VkFramebuffer dst_framebuffer, Texture2D* src_texture, u32 width, u32 height, - void* palette, TlutFormat format, u32 src_format); - -private: - static const size_t NUM_PALETTE_CONVERSION_SHADERS = 3; - - bool CreateBuffers(); - bool CompileShaders(); - - std::array m_shaders = {}; - - std::unique_ptr m_palette_stream_buffer; - VkBufferView m_palette_buffer_view = VK_NULL_HANDLE; - - std::unique_ptr m_uniform_buffer; -}; - -} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index 139221c9c0..3bb92fa3c2 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" @@ -66,17 +65,10 @@ bool TextureCache::Initialize() return false; } - m_texture_encoder = std::make_unique(); - if (!m_texture_encoder->Initialize()) + m_texture_converter = std::make_unique(); + if (!m_texture_converter->Initialize()) { - PanicAlert("Failed to initialize texture encoder."); - return false; - } - - m_palette_texture_converter = std::make_unique(); - if (!m_palette_texture_converter->Initialize()) - { - PanicAlert("Failed to initialize palette texture converter"); + PanicAlert("Failed to initialize texture converter"); return false; } @@ -112,7 +104,7 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* command_buffer = g_command_buffer_mgr->GetCurrentInitCommandBuffer(); } - m_palette_texture_converter->ConvertTexture( + m_texture_converter->ConvertTexture( command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(), unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format, unconverted->format); @@ -156,9 +148,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); @@ -871,8 +863,8 @@ void TextureCache::EncodeYUYVTextureToMemory(void* dst_ptr, u32 dst_width, u32 d 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(); + Texture2D* encoding_texture = m_texture_converter->GetEncodingTexture(); + StagingTexture2D* download_texture = m_texture_converter->GetDownloadTexture(); encoding_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // Use fragment shader to convert RGBA to YUYV. @@ -882,10 +874,10 @@ void TextureCache::EncodeYUYVTextureToMemory(void* dst_ptr, u32 dst_width, u32 d u32 output_width = dst_width / 2; UtilityShaderDraw draw( command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_texture_encoder->GetEncodingRenderPass(), g_object_cache->GetPassthroughVertexShader(), + m_texture_converter->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.BeginRenderPass(m_texture_converter->GetEncodingTextureFramebuffer(), region); draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetLinearSampler()); draw.DrawQuad(0, 0, static_cast(output_width), static_cast(dst_height), src_rect.left, src_rect.top, 0, src_rect.GetWidth(), src_rect.GetHeight(), @@ -942,7 +934,7 @@ void TextureCache::DecodeYUYVTextureFromMemory(TCacheEntry* dst_texture, const v {src_width / 2, src_height, 1} // VkExtent3D imageExtent }; VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - Texture2D* intermediate_texture = m_texture_encoder->GetEncodingTexture(); + Texture2D* intermediate_texture = m_texture_converter->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, @@ -955,7 +947,7 @@ void TextureCache::DecodeYUYVTextureFromMemory(TCacheEntry* dst_texture, const v // Convert from the YUYV data now in the intermediate texture to RGBA in the destination. UtilityShaderDraw draw( command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_texture_encoder->GetEncodingRenderPass(), g_object_cache->GetScreenQuadVertexShader(), + m_texture_converter->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); diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h index 5da9515991..74cd52f182 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.h +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h @@ -12,10 +12,9 @@ namespace Vulkan { -class PaletteTextureConverter; +class TextureConverter; class StateTracker; class Texture2D; -class TextureEncoder; class TextureCache : public TextureCacheBase { @@ -91,9 +90,7 @@ private: std::unique_ptr m_texture_upload_buffer; - std::unique_ptr m_texture_encoder; - - std::unique_ptr m_palette_texture_converter; + std::unique_ptr m_texture_converter; VkShaderModule m_copy_shader = VK_NULL_HANDLE; VkShaderModule m_efb_color_to_tex_shader = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp new file mode 100644 index 0000000000..902d3d118c --- /dev/null +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -0,0 +1,481 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoBackends/Vulkan/TextureConverter.h" + +#include +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/CommonFuncs.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" + +#include "VideoBackends/Vulkan/CommandBufferManager.h" +#include "VideoBackends/Vulkan/FramebufferManager.h" +#include "VideoBackends/Vulkan/ObjectCache.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/Util.h" +#include "VideoBackends/Vulkan/VulkanContext.h" + +#include "VideoCommon/TextureConversionShader.h" +#include "VideoCommon/TextureDecoder.h" + +namespace Vulkan +{ +TextureConverter::TextureConverter() +{ +} + +TextureConverter::~TextureConverter() +{ + for (const auto& it : m_palette_conversion_shaders) + { + if (it != VK_NULL_HANDLE) + 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_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); + + for (VkShaderModule shader : m_texture_encoding_shaders) + { + if (shader != VK_NULL_HANDLE) + vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr); + } +} + +bool TextureConverter::Initialize() +{ + if (!CreateUniformBuffer()) + { + PanicAlert("Failed to create uniform buffer"); + return false; + } + + if (!CompilePaletteConversionShaders()) + { + PanicAlert("Failed to compile palette conversion shaders"); + return false; + } + + if (!CompileEncodingShaders()) + { + PanicAlert("Failed to compile texture encoding shaders"); + return false; + } + + if (!CreateEncodingRenderPass()) + { + PanicAlert("Failed to create encode render pass"); + return false; + } + + if (!CreateEncodingTexture()) + { + PanicAlert("Failed to create encoding texture"); + return false; + } + + if (!CreateDownloadTexture()) + { + PanicAlert("Failed to create download texture"); + return false; + } + + 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) +{ + struct PSUniformBlock + { + float multiplier; + int texel_buffer_offset; + int pad[2]; + }; + + _assert_(static_cast(format) < NUM_PALETTE_CONVERSION_SHADERS); + + size_t palette_size = (src_format & 0xF) == GX_TF_I4 ? 32 : 512; + VkDescriptorSet texel_buffer_descriptor_set; + + // 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) + { + 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) + { + PanicAlert("Failed to allocate space for texture conversion"); + return; + } + } + + // Fill descriptor set #2 (texel buffer) + u32 palette_offset = static_cast(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 + 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); + + // Copy in palette + memcpy(m_palette_stream_buffer->GetCurrentHostPointer(), palette, palette_size); + m_palette_stream_buffer->CommitMemory(palette_size); + + // PS Uniforms/Samplers + PSUniformBlock uniforms = {}; + uniforms.multiplier = (src_format & 0xF) == GX_TF_I4 ? 15.0f : 255.0f; + uniforms.texel_buffer_offset = static_cast(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.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.EndRenderPass(); +} + +void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, + u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat src_format, + bool is_intensity, int scale_by_half, + const EFBRectangle& src_rect) +{ + if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE) + { + ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format); + return; + } + + // Can't do our own draw within a render pass. + StateTracker::GetInstance()->EndRenderPass(); + + 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]); + + // Uniform - int4 of left,top,native_width,scale + s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast(native_width), + scale_by_half ? 2 : 1}; + draw.SetPushConstants(position_uniform, sizeof(position_uniform)); + + // Doesn't make sense to linear filter depth values + draw.SetPSSampler(0, src_texture, (scale_by_half && src_format != PEControl::Z24) ? + g_object_cache->GetLinearSampler() : + g_object_cache->GetPointSampler()); + + u32 render_width = bytes_per_row / sizeof(u32); + u32 render_height = num_blocks_y; + Util::SetViewportAndScissor(g_command_buffer_mgr->GetCurrentCommandBuffer(), 0, 0, render_width, + render_height); + + VkRect2D render_region = {{0, 0}, {render_width, render_height}}; + draw.BeginRenderPass(m_encoding_texture_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); + + // 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); +} + +bool TextureConverter::CreateUniformBuffer() +{ + // 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) + return false; + + // 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 + 0, // VkDeviceSize offset + BUFFER_SIZE // VkDeviceSize range + }; + + VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr, + &m_palette_buffer_view); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: "); + return false; + } + + return true; +} + +bool TextureConverter::CompilePaletteConversionShaders() +{ + static const char PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE[] = R"( + layout(std140, push_constant) uniform PCBlock + { + float multiplier; + int texture_buffer_offset; + } PC; + + layout(set = 1, binding = 0) uniform sampler2DArray samp0; + layout(set = 0, binding = 0) uniform usamplerBuffer samp1; + + layout(location = 0) in vec3 f_uv0; + layout(location = 0) out vec4 ocol0; + + int Convert3To8(int v) + { + // Swizzle bits: 00000123 -> 12312312 + return (v << 5) | (v << 2) | (v >> 1); + } + int Convert4To8(int v) + { + // Swizzle bits: 00001234 -> 12341234 + return (v << 4) | v; + } + int Convert5To8(int v) + { + // Swizzle bits: 00012345 -> 12345123 + return (v << 3) | (v >> 2); + } + int Convert6To8(int v) + { + // Swizzle bits: 00123456 -> 12345612 + return (v << 2) | (v >> 4); + } + float4 DecodePixel_RGB5A3(int val) + { + int r,g,b,a; + if ((val&0x8000) > 0) + { + r=Convert5To8((val>>10) & 0x1f); + g=Convert5To8((val>>5 ) & 0x1f); + b=Convert5To8((val ) & 0x1f); + a=0xFF; + } + else + { + a=Convert3To8((val>>12) & 0x7); + r=Convert4To8((val>>8 ) & 0xf); + g=Convert4To8((val>>4 ) & 0xf); + b=Convert4To8((val ) & 0xf); + } + return float4(r, g, b, a) / 255.0; + } + float4 DecodePixel_RGB565(int val) + { + int r, g, b, a; + r = Convert5To8((val >> 11) & 0x1f); + g = Convert6To8((val >> 5) & 0x3f); + b = Convert5To8((val) & 0x1f); + a = 0xFF; + return float4(r, g, b, a) / 255.0; + } + float4 DecodePixel_IA8(int val) + { + int i = val & 0xFF; + int a = val >> 8; + return float4(i, i, i, a) / 255.0; + } + void main() + { + int src = int(round(texture(samp0, f_uv0).r * PC.multiplier)); + src = int(texelFetch(samp1, src + PC.texture_buffer_offset).r); + src = ((src << 8) & 0xFF00) | (src >> 8); + ocol0 = DECODE(src); + } + + )"; + + std::string palette_ia8_program = StringFromFormat("%s\n%s", "#define DECODE DecodePixel_IA8", + PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); + std::string palette_rgb565_program = StringFromFormat( + "%s\n%s", "#define DECODE DecodePixel_RGB565", PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); + std::string palette_rgb5a3_program = StringFromFormat( + "%s\n%s", "#define DECODE DecodePixel_RGB5A3", PALETTE_CONVERSION_FRAGMENT_SHADER_SOURCE); + + m_palette_conversion_shaders[GX_TL_IA8] = + Util::CompileAndCreateFragmentShader(palette_ia8_program); + m_palette_conversion_shaders[GX_TL_RGB565] = + Util::CompileAndCreateFragmentShader(palette_rgb565_program); + m_palette_conversion_shaders[GX_TL_RGB5A3] = + Util::CompileAndCreateFragmentShader(palette_rgb5a3_program); + + return m_palette_conversion_shaders[GX_TL_IA8] != VK_NULL_HANDLE && + m_palette_conversion_shaders[GX_TL_RGB565] != VK_NULL_HANDLE && + m_palette_conversion_shaders[GX_TL_RGB5A3] != VK_NULL_HANDLE; +} + +bool TextureConverter::CompileEncodingShaders() +{ + // Texture encoding shaders + static const u32 texture_encoding_shader_formats[] = { + GX_TF_I4, GX_TF_I8, GX_TF_IA4, GX_TF_IA8, GX_TF_RGB565, GX_TF_RGB5A3, GX_TF_RGBA8, + GX_CTF_R4, GX_CTF_RA4, GX_CTF_RA8, GX_CTF_A8, GX_CTF_R8, GX_CTF_G8, GX_CTF_B8, + GX_CTF_RG8, GX_CTF_GB8, GX_CTF_Z8H, GX_TF_Z8, GX_CTF_Z16R, GX_TF_Z16, GX_TF_Z24X8, + GX_CTF_Z4, GX_CTF_Z8M, GX_CTF_Z8L, GX_CTF_Z16L}; + for (u32 format : texture_encoding_shader_formats) + { + 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) + return false; + } + + return true; +} + +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_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL}}; + + VkAttachmentReference color_attachment_references[] = { + {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; + + VkSubpassDescription subpass_descriptions[] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, + color_attachment_references, nullptr, nullptr, 0, + nullptr}}; + + VkSubpassDependency dependancies[] = { + {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}}; + + VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + nullptr, + 0, + static_cast(ArraySize(attachments)), + attachments, + static_cast(ArraySize(subpass_descriptions)), + subpass_descriptions, + static_cast(ArraySize(dependancies)), + dependancies}; + + VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, + &m_encoding_render_pass); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateRenderPass (Encode) failed: "); + return false; + } + + return true; +} + +bool TextureConverter::CreateEncodingTexture() +{ + m_encoding_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) + return false; + + VkImageView framebuffer_attachments[] = {m_encoding_texture->GetView()}; + VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + nullptr, + 0, + m_encoding_render_pass, + static_cast(ArraySize(framebuffer_attachments)), + framebuffer_attachments, + m_encoding_texture->GetWidth(), + m_encoding_texture->GetHeight(), + m_encoding_texture->GetLayers()}; + + VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, + &m_encoding_texture_framebuffer); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); + return false; + } + + return true; +} + +bool TextureConverter::CreateDownloadTexture() +{ + m_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; +} + +} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/TextureEncoder.h b/Source/Core/VideoBackends/Vulkan/TextureConverter.h similarity index 54% rename from Source/Core/VideoBackends/Vulkan/TextureEncoder.h rename to Source/Core/VideoBackends/Vulkan/TextureConverter.h index c3fa68c752..3dcf4683ef 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureEncoder.h +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.h @@ -8,8 +8,9 @@ #include #include "Common/CommonTypes.h" -#include "VideoBackends/Vulkan/VulkanLoader.h" +#include "VideoBackends/Vulkan/StreamBuffer.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VideoCommon.h" namespace Vulkan @@ -17,11 +18,11 @@ namespace Vulkan class StagingTexture2D; class Texture2D; -class TextureEncoder +class TextureConverter { public: - TextureEncoder(); - ~TextureEncoder(); + TextureConverter(); + ~TextureConverter(); VkRenderPass GetEncodingRenderPass() const { return m_encoding_render_pass; } Texture2D* GetEncodingTexture() const { return m_encoding_texture.get(); } @@ -29,26 +30,38 @@ public: StagingTexture2D* GetDownloadTexture() const { return m_download_texture.get(); } bool Initialize(); + void ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass, + VkFramebuffer dst_framebuffer, Texture2D* src_texture, u32 width, u32 height, + void* palette, TlutFormat format, u32 src_format); + // Uses an encoding shader to copy src_texture to dest_ptr. - // Assumes that no render pass is currently in progress. - // WARNING: Executes the current command buffer. - void EncodeTextureToRam(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width, - u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, bool is_intensity, int scale_by_half, - const EFBRectangle& source); + // NOTE: Executes the current command buffer. + void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + PEControl::PixelFormat src_format, bool is_intensity, + int scale_by_half, const EFBRectangle& source); private: - // From OGL. static const u32 NUM_TEXTURE_ENCODING_SHADERS = 64; 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 size_t NUM_PALETTE_CONVERSION_SHADERS = 3; - bool CompileShaders(); + bool CreateUniformBuffer(); + bool CompilePaletteConversionShaders(); + bool CompileEncodingShaders(); bool CreateEncodingRenderPass(); bool CreateEncodingTexture(); bool CreateDownloadTexture(); + std::array m_palette_conversion_shaders = {}; + + std::unique_ptr m_palette_stream_buffer; + VkBufferView m_palette_buffer_view = VK_NULL_HANDLE; + + std::unique_ptr m_uniform_buffer; + std::array m_texture_encoding_shaders = {}; VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp b/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp deleted file mode 100644 index 08948d97cb..0000000000 --- a/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/Vulkan/TextureEncoder.h" - -#include -#include - -#include "Common/CommonFuncs.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" - -#include "VideoBackends/Vulkan/CommandBufferManager.h" -#include "VideoBackends/Vulkan/ObjectCache.h" -#include "VideoBackends/Vulkan/Renderer.h" -#include "VideoBackends/Vulkan/StagingTexture2D.h" -#include "VideoBackends/Vulkan/StateTracker.h" -#include "VideoBackends/Vulkan/Texture2D.h" -#include "VideoBackends/Vulkan/Util.h" -#include "VideoBackends/Vulkan/VulkanContext.h" - -#include "VideoCommon/TextureConversionShader.h" -#include "VideoCommon/TextureDecoder.h" - -namespace Vulkan -{ -TextureEncoder::TextureEncoder() -{ -} - -TextureEncoder::~TextureEncoder() -{ - 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); - - for (VkShaderModule shader : m_texture_encoding_shaders) - { - if (shader != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr); - } -} - -bool TextureEncoder::Initialize() -{ - if (!CompileShaders()) - { - PanicAlert("Failed to compile shaders"); - return false; - } - - if (!CreateEncodingRenderPass()) - { - PanicAlert("Failed to create encode render pass"); - return false; - } - - if (!CreateEncodingTexture()) - { - PanicAlert("Failed to create encoding texture"); - return false; - } - - if (!CreateDownloadTexture()) - { - PanicAlert("Failed to create download texture"); - return false; - } - - return true; -} - -void TextureEncoder::EncodeTextureToRam(VkImageView src_texture, u8* dest_ptr, u32 format, - u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, PEControl::PixelFormat src_format, - bool is_intensity, int scale_by_half, - const EFBRectangle& src_rect) -{ - if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE) - { - ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format); - return; - } - - // Can't do our own draw within a render pass. - StateTracker::GetInstance()->EndRenderPass(); - - 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]); - - // Uniform - int4 of left,top,native_width,scale - s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast(native_width), - scale_by_half ? 2 : 1}; - draw.SetPushConstants(position_uniform, sizeof(position_uniform)); - - // Doesn't make sense to linear filter depth values - draw.SetPSSampler(0, src_texture, (scale_by_half && src_format != PEControl::Z24) ? - g_object_cache->GetLinearSampler() : - g_object_cache->GetPointSampler()); - - u32 render_width = bytes_per_row / sizeof(u32); - u32 render_height = num_blocks_y; - Util::SetViewportAndScissor(g_command_buffer_mgr->GetCurrentCommandBuffer(), 0, 0, render_width, - render_height); - - // TODO: We could use compute shaders here. - VkRect2D render_region = {{0, 0}, {render_width, render_height}}; - draw.BeginRenderPass(m_encoding_texture_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); - - // 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); -} - -bool TextureEncoder::CompileShaders() -{ - // Texture encoding shaders - static const u32 texture_encoding_shader_formats[] = { - GX_TF_I4, GX_TF_I8, GX_TF_IA4, GX_TF_IA8, GX_TF_RGB565, GX_TF_RGB5A3, GX_TF_RGBA8, - GX_CTF_R4, GX_CTF_RA4, GX_CTF_RA8, GX_CTF_A8, GX_CTF_R8, GX_CTF_G8, GX_CTF_B8, - GX_CTF_RG8, GX_CTF_GB8, GX_CTF_Z8H, GX_TF_Z8, GX_CTF_Z16R, GX_TF_Z16, GX_TF_Z24X8, - GX_CTF_Z4, GX_CTF_Z8M, GX_CTF_Z8L, GX_CTF_Z16L}; - for (u32 format : texture_encoding_shader_formats) - { - 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) - return false; - } - - return true; -} - -bool TextureEncoder::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_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL}}; - - VkAttachmentReference color_attachment_references[] = { - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkSubpassDescription subpass_descriptions[] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, - color_attachment_references, nullptr, nullptr, 0, - nullptr}}; - - VkSubpassDependency dependancies[] = { - {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}}; - - VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - 0, - static_cast(ArraySize(attachments)), - attachments, - static_cast(ArraySize(subpass_descriptions)), - subpass_descriptions, - static_cast(ArraySize(dependancies)), - dependancies}; - - VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, - &m_encoding_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (Encode) failed: "); - return false; - } - - return true; -} - -bool TextureEncoder::CreateEncodingTexture() -{ - // From OGL: Why do we create a 1024 height texture? - m_encoding_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) - return false; - - VkImageView framebuffer_attachments[] = {m_encoding_texture->GetView()}; - VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - 0, - m_encoding_render_pass, - static_cast(ArraySize(framebuffer_attachments)), - framebuffer_attachments, - m_encoding_texture->GetWidth(), - m_encoding_texture->GetHeight(), - m_encoding_texture->GetLayers()}; - - VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_encoding_texture_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - - return true; -} - -bool TextureEncoder::CreateDownloadTexture() -{ - m_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; -} - -} // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj index 64ac839164..c7bdada31b 100644 --- a/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj +++ b/Source/Core/VideoBackends/Vulkan/Vulkan.vcxproj @@ -53,12 +53,11 @@ - + - @@ -78,11 +77,10 @@ - + - @@ -116,4 +114,4 @@ - + \ No newline at end of file