Vulkan: Combine PaletteTextureConverter and TextureEncoder classes
This commit is contained in:
parent
804af42ccc
commit
add638538b
|
@ -3,7 +3,6 @@ set(SRCS
|
||||||
CommandBufferManager.cpp
|
CommandBufferManager.cpp
|
||||||
FramebufferManager.cpp
|
FramebufferManager.cpp
|
||||||
ObjectCache.cpp
|
ObjectCache.cpp
|
||||||
PaletteTextureConverter.cpp
|
|
||||||
PerfQuery.cpp
|
PerfQuery.cpp
|
||||||
RasterFont.cpp
|
RasterFont.cpp
|
||||||
Renderer.cpp
|
Renderer.cpp
|
||||||
|
@ -15,7 +14,7 @@ set(SRCS
|
||||||
SwapChain.cpp
|
SwapChain.cpp
|
||||||
Texture2D.cpp
|
Texture2D.cpp
|
||||||
TextureCache.cpp
|
TextureCache.cpp
|
||||||
TextureEncoder.cpp
|
TextureConverter.cpp
|
||||||
Util.cpp
|
Util.cpp
|
||||||
VertexFormat.cpp
|
VertexFormat.cpp
|
||||||
VertexManager.cpp
|
VertexManager.cpp
|
||||||
|
|
|
@ -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 <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#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<size_t>(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<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
|
|
||||||
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<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.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
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2016 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_shaders = {};
|
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> m_palette_stream_buffer;
|
|
||||||
VkBufferView m_palette_buffer_view = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> m_uniform_buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
|
|
@ -17,13 +17,12 @@
|
||||||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||||
#include "VideoBackends/Vulkan/FramebufferManager.h"
|
#include "VideoBackends/Vulkan/FramebufferManager.h"
|
||||||
#include "VideoBackends/Vulkan/ObjectCache.h"
|
#include "VideoBackends/Vulkan/ObjectCache.h"
|
||||||
#include "VideoBackends/Vulkan/PaletteTextureConverter.h"
|
|
||||||
#include "VideoBackends/Vulkan/Renderer.h"
|
#include "VideoBackends/Vulkan/Renderer.h"
|
||||||
#include "VideoBackends/Vulkan/StagingTexture2D.h"
|
#include "VideoBackends/Vulkan/StagingTexture2D.h"
|
||||||
#include "VideoBackends/Vulkan/StateTracker.h"
|
#include "VideoBackends/Vulkan/StateTracker.h"
|
||||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||||
#include "VideoBackends/Vulkan/Texture2D.h"
|
#include "VideoBackends/Vulkan/Texture2D.h"
|
||||||
#include "VideoBackends/Vulkan/TextureEncoder.h"
|
#include "VideoBackends/Vulkan/TextureConverter.h"
|
||||||
#include "VideoBackends/Vulkan/Util.h"
|
#include "VideoBackends/Vulkan/Util.h"
|
||||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
|
|
||||||
|
@ -66,17 +65,10 @@ bool TextureCache::Initialize()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_texture_encoder = std::make_unique<TextureEncoder>();
|
m_texture_converter = std::make_unique<TextureConverter>();
|
||||||
if (!m_texture_encoder->Initialize())
|
if (!m_texture_converter->Initialize())
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to initialize texture encoder.");
|
PanicAlert("Failed to initialize texture converter");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_palette_texture_converter = std::make_unique<PaletteTextureConverter>();
|
|
||||||
if (!m_palette_texture_converter->Initialize())
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to initialize palette texture converter");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +104,7 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
|
||||||
command_buffer = g_command_buffer_mgr->GetCurrentInitCommandBuffer();
|
command_buffer = g_command_buffer_mgr->GetCurrentInitCommandBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_palette_texture_converter->ConvertTexture(
|
m_texture_converter->ConvertTexture(
|
||||||
command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(),
|
command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(),
|
||||||
unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format,
|
unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format,
|
||||||
unconverted->format);
|
unconverted->format);
|
||||||
|
@ -156,7 +148,7 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_
|
||||||
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
m_texture_encoder->EncodeTextureToRam(src_texture->GetView(), dst, format, native_width,
|
m_texture_converter->EncodeTextureToMemory(src_texture->GetView(), dst, format, native_width,
|
||||||
bytes_per_row, num_blocks_y, memory_stride, src_format,
|
bytes_per_row, num_blocks_y, memory_stride, src_format,
|
||||||
is_intensity, scale_by_half, src_rect);
|
is_intensity, scale_by_half, src_rect);
|
||||||
|
|
||||||
|
@ -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);
|
src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
// Borrow framebuffer from EFB2RAM encoder.
|
// Borrow framebuffer from EFB2RAM encoder.
|
||||||
Texture2D* encoding_texture = m_texture_encoder->GetEncodingTexture();
|
Texture2D* encoding_texture = m_texture_converter->GetEncodingTexture();
|
||||||
StagingTexture2D* download_texture = m_texture_encoder->GetDownloadTexture();
|
StagingTexture2D* download_texture = m_texture_converter->GetDownloadTexture();
|
||||||
encoding_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
encoding_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
// Use fragment shader to convert RGBA to YUYV.
|
// 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;
|
u32 output_width = dst_width / 2;
|
||||||
UtilityShaderDraw draw(
|
UtilityShaderDraw draw(
|
||||||
command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD),
|
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);
|
VK_NULL_HANDLE, m_rgb_to_yuyv_shader);
|
||||||
VkRect2D region = {{0, 0}, {output_width, dst_height}};
|
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.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,
|
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(),
|
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
|
{src_width / 2, src_height, 1} // VkExtent3D imageExtent
|
||||||
};
|
};
|
||||||
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
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);
|
intermediate_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
vkCmdCopyBufferToImage(command_buffer, m_texture_upload_buffer->GetBuffer(),
|
vkCmdCopyBufferToImage(command_buffer, m_texture_upload_buffer->GetBuffer(),
|
||||||
intermediate_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
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.
|
// Convert from the YUYV data now in the intermediate texture to RGBA in the destination.
|
||||||
UtilityShaderDraw draw(
|
UtilityShaderDraw draw(
|
||||||
command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD),
|
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);
|
VK_NULL_HANDLE, m_yuyv_to_rgb_shader);
|
||||||
VkRect2D region = {{0, 0}, {src_width, src_height}};
|
VkRect2D region = {{0, 0}, {src_width, src_height}};
|
||||||
draw.BeginRenderPass(dst_texture->GetFramebuffer(), region);
|
draw.BeginRenderPass(dst_texture->GetFramebuffer(), region);
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
class PaletteTextureConverter;
|
class TextureConverter;
|
||||||
class StateTracker;
|
class StateTracker;
|
||||||
class Texture2D;
|
class Texture2D;
|
||||||
class TextureEncoder;
|
|
||||||
|
|
||||||
class TextureCache : public TextureCacheBase
|
class TextureCache : public TextureCacheBase
|
||||||
{
|
{
|
||||||
|
@ -91,9 +90,7 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> m_texture_upload_buffer;
|
std::unique_ptr<StreamBuffer> m_texture_upload_buffer;
|
||||||
|
|
||||||
std::unique_ptr<TextureEncoder> m_texture_encoder;
|
std::unique_ptr<TextureConverter> m_texture_converter;
|
||||||
|
|
||||||
std::unique_ptr<PaletteTextureConverter> m_palette_texture_converter;
|
|
||||||
|
|
||||||
VkShaderModule m_copy_shader = VK_NULL_HANDLE;
|
VkShaderModule m_copy_shader = VK_NULL_HANDLE;
|
||||||
VkShaderModule m_efb_color_to_tex_shader = VK_NULL_HANDLE;
|
VkShaderModule m_efb_color_to_tex_shader = VK_NULL_HANDLE;
|
||||||
|
|
|
@ -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 <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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<size_t>(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<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
|
||||||
|
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<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.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<s32>(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<u32>(ArraySize(attachments)),
|
||||||
|
attachments,
|
||||||
|
static_cast<u32>(ArraySize(subpass_descriptions)),
|
||||||
|
subpass_descriptions,
|
||||||
|
static_cast<u32>(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<u32>(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
|
|
@ -8,8 +8,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||||
#include "VideoCommon/BPMemory.h"
|
#include "VideoCommon/BPMemory.h"
|
||||||
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
|
@ -17,11 +18,11 @@ namespace Vulkan
|
||||||
class StagingTexture2D;
|
class StagingTexture2D;
|
||||||
class Texture2D;
|
class Texture2D;
|
||||||
|
|
||||||
class TextureEncoder
|
class TextureConverter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextureEncoder();
|
TextureConverter();
|
||||||
~TextureEncoder();
|
~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_texture.get(); }
|
||||||
|
@ -29,26 +30,38 @@ public:
|
||||||
StagingTexture2D* GetDownloadTexture() const { return m_download_texture.get(); }
|
StagingTexture2D* GetDownloadTexture() const { return m_download_texture.get(); }
|
||||||
bool Initialize();
|
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.
|
// Uses an encoding shader to copy src_texture to dest_ptr.
|
||||||
// Assumes that no render pass is currently in progress.
|
// NOTE: Executes the current command buffer.
|
||||||
// WARNING: Executes the current command buffer.
|
void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width,
|
||||||
void EncodeTextureToRam(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width,
|
|
||||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||||
PEControl::PixelFormat src_format, bool is_intensity, int scale_by_half,
|
PEControl::PixelFormat src_format, bool is_intensity,
|
||||||
const EFBRectangle& source);
|
int scale_by_half, const EFBRectangle& source);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// From OGL.
|
|
||||||
static const u32 NUM_TEXTURE_ENCODING_SHADERS = 64;
|
static const u32 NUM_TEXTURE_ENCODING_SHADERS = 64;
|
||||||
static const u32 ENCODING_TEXTURE_WIDTH = EFB_WIDTH * 4;
|
static const u32 ENCODING_TEXTURE_WIDTH = EFB_WIDTH * 4;
|
||||||
static const u32 ENCODING_TEXTURE_HEIGHT = 1024;
|
static const u32 ENCODING_TEXTURE_HEIGHT = 1024;
|
||||||
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;
|
||||||
|
|
||||||
bool CompileShaders();
|
bool CreateUniformBuffer();
|
||||||
|
bool CompilePaletteConversionShaders();
|
||||||
|
bool CompileEncodingShaders();
|
||||||
bool CreateEncodingRenderPass();
|
bool CreateEncodingRenderPass();
|
||||||
bool CreateEncodingTexture();
|
bool CreateEncodingTexture();
|
||||||
bool CreateDownloadTexture();
|
bool CreateDownloadTexture();
|
||||||
|
|
||||||
|
std::array<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_shaders = {};
|
||||||
|
|
||||||
|
std::unique_ptr<StreamBuffer> m_palette_stream_buffer;
|
||||||
|
VkBufferView m_palette_buffer_view = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::unique_ptr<StreamBuffer> m_uniform_buffer;
|
||||||
|
|
||||||
std::array<VkShaderModule, NUM_TEXTURE_ENCODING_SHADERS> m_texture_encoding_shaders = {};
|
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;
|
|
@ -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 <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#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<s32>(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<u32>(ArraySize(attachments)),
|
|
||||||
attachments,
|
|
||||||
static_cast<u32>(ArraySize(subpass_descriptions)),
|
|
||||||
subpass_descriptions,
|
|
||||||
static_cast<u32>(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<u32>(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
|
|
|
@ -53,12 +53,11 @@
|
||||||
<ClCompile Include="CommandBufferManager.cpp" />
|
<ClCompile Include="CommandBufferManager.cpp" />
|
||||||
<ClCompile Include="FramebufferManager.cpp" />
|
<ClCompile Include="FramebufferManager.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="PaletteTextureConverter.cpp" />
|
<ClCompile Include="TextureConverter.cpp" />
|
||||||
<ClCompile Include="PerfQuery.cpp" />
|
<ClCompile Include="PerfQuery.cpp" />
|
||||||
<ClCompile Include="RasterFont.cpp" />
|
<ClCompile Include="RasterFont.cpp" />
|
||||||
<ClCompile Include="StagingBuffer.cpp" />
|
<ClCompile Include="StagingBuffer.cpp" />
|
||||||
<ClCompile Include="StagingTexture2D.cpp" />
|
<ClCompile Include="StagingTexture2D.cpp" />
|
||||||
<ClCompile Include="TextureEncoder.cpp" />
|
|
||||||
<ClCompile Include="Util.cpp" />
|
<ClCompile Include="Util.cpp" />
|
||||||
<ClCompile Include="VertexFormat.cpp" />
|
<ClCompile Include="VertexFormat.cpp" />
|
||||||
<ClCompile Include="ObjectCache.cpp" />
|
<ClCompile Include="ObjectCache.cpp" />
|
||||||
|
@ -78,11 +77,10 @@
|
||||||
<ClInclude Include="CommandBufferManager.h" />
|
<ClInclude Include="CommandBufferManager.h" />
|
||||||
<ClInclude Include="FramebufferManager.h" />
|
<ClInclude Include="FramebufferManager.h" />
|
||||||
<ClInclude Include="Constants.h" />
|
<ClInclude Include="Constants.h" />
|
||||||
<ClInclude Include="PaletteTextureConverter.h" />
|
<ClInclude Include="TextureConverter.h" />
|
||||||
<ClInclude Include="RasterFont.h" />
|
<ClInclude Include="RasterFont.h" />
|
||||||
<ClInclude Include="StagingBuffer.h" />
|
<ClInclude Include="StagingBuffer.h" />
|
||||||
<ClInclude Include="StagingTexture2D.h" />
|
<ClInclude Include="StagingTexture2D.h" />
|
||||||
<ClInclude Include="TextureEncoder.h" />
|
|
||||||
<ClInclude Include="Util.h" />
|
<ClInclude Include="Util.h" />
|
||||||
<ClInclude Include="VertexFormat.h" />
|
<ClInclude Include="VertexFormat.h" />
|
||||||
<ClInclude Include="PerfQuery.h" />
|
<ClInclude Include="PerfQuery.h" />
|
||||||
|
|
Loading…
Reference in New Issue