VideoBackends: Support updated texture encoding shader generators

This commit is contained in:
Stenzek 2017-04-04 23:55:36 +10:00
parent 3847e226ab
commit e9850aa0f2
20 changed files with 194 additions and 279 deletions

View File

@ -75,11 +75,11 @@ void PSTextureEncoder::Shutdown()
{ {
m_ready = false; m_ready = false;
for (auto& it : m_staticShaders) for (auto& it : m_encoding_shaders)
{ {
SAFE_RELEASE(it.second); SAFE_RELEASE(it.second);
} }
m_staticShaders.clear(); m_encoding_shaders.clear();
SAFE_RELEASE(m_encodeParams); SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage); SAFE_RELEASE(m_outStage);
@ -87,9 +87,9 @@ void PSTextureEncoder::Shutdown()
SAFE_RELEASE(m_out); SAFE_RELEASE(m_out);
} }
void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void PSTextureEncoder::Encode(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
if (!m_ready) // Make sure we initialized OK if (!m_ready) // Make sure we initialized OK
return; return;
@ -120,10 +120,10 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
EFBEncodeParams params; EFBEncodeParams params;
params.SrcLeft = srcRect.left; params.SrcLeft = src_rect.left;
params.SrcTop = srcRect.top; params.SrcTop = src_rect.top;
params.DestWidth = native_width; params.DestWidth = native_width;
params.ScaleFactor = scaleByHalf ? 2 : 1; params.ScaleFactor = scale_by_half ? 2 : 1;
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0); D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(m_encodeParams); D3D::stateman->SetPixelConstants(m_encodeParams);
@ -131,15 +131,15 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
// TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will
// need more complex down filtering to average all pixels and produce the correct result. // need more complex down filtering to average all pixels and produce the correct result.
// Also, box filtering won't be correct for anything other than 1x IR // Also, box filtering won't be correct for anything other than 1x IR
if (scaleByHalf || g_ActiveConfig.iEFBScale != SCALE_1X) if (scale_by_half || g_ActiveConfig.iEFBScale != SCALE_1X)
D3D::SetLinearCopySampler(); D3D::SetLinearCopySampler();
else else
D3D::SetPointCopySampler(); D3D::SetPointCopySampler();
D3D::drawShadedTexQuad( D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(),
pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), g_renderer->GetTargetHeight(), GetEncodingPixelShader(format),
SetStaticShader(format, is_depth_copy, isIntensity, scaleByHalf), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); VertexShaderCache::GetSimpleInputLayout());
// Copy to staging buffer // Copy to staging buffer
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1);
@ -168,43 +168,18 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
FramebufferManager::GetEFBDepthTexture()->GetDSV()); FramebufferManager::GetEFBDepthTexture()->GetDSV());
} }
ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, bool is_depth_copy, ID3D11PixelShader* PSTextureEncoder::GetEncodingPixelShader(const EFBCopyFormat& format)
bool isIntensity, bool scaleByHalf)
{ {
ComboKey key = MakeComboKey(dstFormat, is_depth_copy, isIntensity, scaleByHalf); auto iter = m_encoding_shaders.find(format);
if (iter != m_encoding_shaders.end())
ComboMap::iterator it = m_staticShaders.find(key); return iter->second;
if (it == m_staticShaders.end())
{
INFO_LOG(VIDEO,
"Compiling efb encoding shader for dstFormat 0x%X, is_depth_copy %d, isIntensity "
"%d, scaleByHalf %d",
dstFormat, is_depth_copy, isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
u32 format = dstFormat;
if (is_depth_copy)
{
format |= _GX_TF_ZTF;
if (dstFormat == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
{
if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity))
format |= _GX_TF_CTF;
}
D3DBlob* bytecode = nullptr; D3DBlob* bytecode = nullptr;
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
if (!D3D::CompilePixelShader(shader, &bytecode)) if (!D3D::CompilePixelShader(shader, &bytecode))
{ {
WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, is_depth_copy %d, isIntensity %d, " PanicAlert("Failed to compile texture encoding shader.");
"scaleByHalf %d failed to compile", m_encoding_shaders[format] = nullptr;
dstFormat, is_depth_copy, isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
m_staticShaders[key] = nullptr;
return nullptr; return nullptr;
} }
@ -213,16 +188,7 @@ ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, boo
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader); D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
char debugName[255] = {}; m_encoding_shaders.emplace(format, newShader);
sprintf_s(debugName, return newShader;
"efb encoder pixel shader (dst:%d, is_depth_copy:%d, intensity:%d, scale:%d)",
dstFormat, is_depth_copy, isIntensity, scaleByHalf);
D3D::SetDebugObjectName(newShader, debugName);
it = m_staticShaders.emplace(key, newShader).first;
bytecode->Release();
}
return it->second;
} }
} }

View File

@ -7,6 +7,7 @@
#include <map> #include <map>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/TextureConversionShader.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
struct ID3D11Texture2D; struct ID3D11Texture2D;
@ -31,32 +32,19 @@ public:
void Init(); void Init();
void Shutdown(); void Shutdown();
void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect,
bool scaleByHalf); bool scale_by_half);
private: private:
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyFormat& format);
bool m_ready; bool m_ready;
ID3D11Texture2D* m_out; ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV; ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage; ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams; ID3D11Buffer* m_encodeParams;
std::map<EFBCopyFormat, ID3D11PixelShader*> m_encoding_shaders;
ID3D11PixelShader* SetStaticShader(unsigned int dstFormat, bool is_depth_copy, bool isIntensity,
bool scaleByHalf);
typedef unsigned int ComboKey; // Key for a shader combination
ComboKey MakeComboKey(unsigned int dstFormat, bool is_depth_copy, bool isIntensity,
bool scaleByHalf)
{
return (dstFormat << 4) | (static_cast<int>(is_depth_copy) << 2) |
(isIntensity ? (1 << 1) : 0) | (scaleByHalf ? (1 << 0) : 0);
}
typedef std::map<ComboKey, ID3D11PixelShader*> ComboMap;
ComboMap m_staticShaders;
}; };
} }

View File

@ -241,12 +241,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe
g_renderer->RestoreAPIState(); g_renderer->RestoreAPIState();
} }
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride,
is_depth_copy, srcRect, isIntensity, scaleByHalf); is_depth_copy, src_rect, scale_by_half);
} }
const char palette_shader[] = const char palette_shader[] =

View File

@ -51,9 +51,9 @@ private:
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette,
TlutFormat format) override; TlutFormat format) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool scaleByHalf) override; const EFBRectangle& src_rect, bool scale_by_half) override;
bool CompileShaders() override { return true; } bool CompileShaders() override { return true; }
void DeleteShaders() override {} void DeleteShaders() override {}

View File

@ -101,18 +101,18 @@ void PSTextureEncoder::Shutdown()
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out_readback_buffer); D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out_readback_buffer);
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_encode_params_buffer); D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_encode_params_buffer);
for (auto& it : m_static_shaders_blobs) for (auto& it : m_shader_blobs)
{ {
SAFE_RELEASE(it); SAFE_RELEASE(it);
} }
m_static_shaders_blobs.clear(); m_shader_blobs.clear();
m_static_shaders_map.clear(); m_encoding_shaders.clear();
} }
void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void PSTextureEncoder::Encode(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
if (!m_ready) // Make sure we initialized OK if (!m_ready) // Make sure we initialized OK
return; return;
@ -167,8 +167,7 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
D3D::DrawShadedTexQuad( D3D::DrawShadedTexQuad(
efb_source, target_rect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), efb_source, target_rect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(),
SetStaticShader(format, is_depth_copy, is_intensity, scale_by_half), GetEncodingPixelShader(format), StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0f, 0, StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0f, 0,
DXGI_FORMAT_B8G8R8A8_UNORM, false, false /* Render target is not multisampled */ DXGI_FORMAT_B8G8R8A8_UNORM, false, false /* Render target is not multisampled */
); );
@ -223,53 +222,27 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
m_out_readback_buffer->Unmap(0, &write_range); m_out_readback_buffer->Unmap(0, &write_range);
} }
D3D12_SHADER_BYTECODE PSTextureEncoder::SetStaticShader(unsigned int dst_format, bool is_depth_copy, D3D12_SHADER_BYTECODE PSTextureEncoder::GetEncodingPixelShader(const EFBCopyFormat& format)
bool is_intensity, bool scale_by_half)
{ {
ComboKey key = MakeComboKey(dst_format, is_depth_copy, is_intensity, scale_by_half); auto iter = m_encoding_shaders.find(format);
if (iter != m_encoding_shaders.end())
ComboMap::iterator it = m_static_shaders_map.find(key); return iter->second;
if (it == m_static_shaders_map.end())
{
INFO_LOG(VIDEO, "Compiling efb encoding shader for dst_format 0x%X, is_depth_copy %d, "
"is_intensity %d, scale_by_half %d",
dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0);
u32 format = dst_format;
if (is_depth_copy)
{
format |= _GX_TF_ZTF;
if (dst_format == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
{
if (dst_format > GX_TF_RGBA8 || (dst_format < GX_TF_RGB565 && !is_intensity))
format |= _GX_TF_CTF;
}
ID3DBlob* bytecode = nullptr; ID3DBlob* bytecode = nullptr;
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
if (!D3D::CompilePixelShader(shader, &bytecode)) if (!D3D::CompilePixelShader(shader, &bytecode))
{ {
WARN_LOG(VIDEO, "EFB encoder shader for dst_format 0x%X, is_depth_copy %d, is_intensity %d, " PanicAlert("Failed to compile texture encoding shader.");
"scale_by_half %d failed to compile", m_encoding_shaders[format] = {};
dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0);
m_static_shaders_blobs[key] = {};
return {}; return {};
} }
D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()}; D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()};
m_encoding_shaders.emplace(format, new_shader);
it = m_static_shaders_map.emplace(key, new_shader).first;
// Keep track of the ID3DBlobs, so we can free them upon shutdown. // Keep track of the ID3DBlobs, so we can free them upon shutdown.
m_static_shaders_blobs.push_back(bytecode); m_shader_blobs.push_back(bytecode);
}
return it->second; return new_shader;
} }
} }

View File

@ -9,6 +9,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DBase.h"
#include "VideoCommon/TextureConversionShader.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
namespace DX12 namespace DX12
@ -20,11 +21,13 @@ public:
void Init(); void Init();
void Shutdown(); void Shutdown();
void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect,
bool is_intensity, bool scale_by_half); bool scale_by_half);
private: private:
D3D12_SHADER_BYTECODE GetEncodingPixelShader(const EFBCopyFormat& format);
bool m_ready = false; bool m_ready = false;
ID3D12Resource* m_out = nullptr; ID3D12Resource* m_out = nullptr;
@ -35,19 +38,7 @@ private:
ID3D12Resource* m_encode_params_buffer = nullptr; ID3D12Resource* m_encode_params_buffer = nullptr;
void* m_encode_params_buffer_data = nullptr; void* m_encode_params_buffer_data = nullptr;
D3D12_SHADER_BYTECODE SetStaticShader(unsigned int dst_format, bool is_depth_copy, std::map<EFBCopyFormat, D3D12_SHADER_BYTECODE> m_encoding_shaders;
bool is_intensity, bool scale_by_half); std::vector<ID3DBlob*> m_shader_blobs;
using ComboKey = unsigned int; // Key for a shader combination
static ComboKey MakeComboKey(unsigned int dst_format, bool is_depth_copy, bool is_intensity,
bool scale_by_half)
{
return (dst_format << 4) | (is_depth_copy << 2) | (is_intensity ? (1 << 1) : 0) |
(scale_by_half ? (1 << 0) : 0);
}
using ComboMap = std::map<ComboKey, D3D12_SHADER_BYTECODE>;
ComboMap m_static_shaders_map;
std::vector<ID3DBlob*> m_static_shaders_blobs;
}; };
} }

View File

@ -306,12 +306,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe
g_renderer->RestoreAPIState(); g_renderer->RestoreAPIState();
} }
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride,
is_depth_copy, srcRect, isIntensity, scaleByHalf); is_depth_copy, src_rect, scale_by_half);
} }
static const constexpr char s_palette_shader_hlsl[] = static const constexpr char s_palette_shader_hlsl[] =

View File

@ -60,9 +60,9 @@ private:
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette,
TlutFormat format) override; TlutFormat format) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool is_intensity, bool scale_by_half) override; const EFBRectangle& src_rect, bool scale_by_half) override;
bool CompileShaders() override { return true; } bool CompileShaders() override { return true; }
void DeleteShaders() override {} void DeleteShaders() override {}

View File

@ -20,9 +20,9 @@ public:
{ {
} }
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool is_intensity, bool scale_by_half) override const EFBRectangle& src_rect, bool scale_by_half) override
{ {
} }

View File

@ -288,13 +288,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe
g_renderer->RestoreAPIState(); g_renderer->RestoreAPIState();
} }
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
TextureConverter::EncodeToRamFromTexture(dst, format, native_width, bytes_per_row, num_blocks_y, TextureConverter::EncodeToRamFromTexture(dst, format, native_width, bytes_per_row, num_blocks_y,
memory_stride, is_depth_copy, isIntensity, scaleByHalf, memory_stride, is_depth_copy, src_rect, scale_by_half);
srcRect);
} }
TextureCache::TextureCache() TextureCache::TextureCache()

View File

@ -58,9 +58,9 @@ private:
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette,
TlutFormat format) override; TlutFormat format) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool scaleByHalf) override; const EFBRectangle& src_rect, bool scale_by_half) override;
bool CompileShaders() override; bool CompileShaders() override;
void DeleteShaders() override; void DeleteShaders() override;

View File

@ -45,10 +45,12 @@ static int s_rgbToYuyvUniform_loc;
static SHADER s_yuyvToRgbProgram; static SHADER s_yuyvToRgbProgram;
// Not all slots are taken - but who cares. struct EncodingProgram
const u32 NUM_ENCODING_PROGRAMS = 64; {
static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS]; SHADER program;
static int s_encodingUniforms[NUM_ENCODING_PROGRAMS]; GLint copy_position_uniform;
};
static std::map<EFBCopyFormat, EncodingProgram> s_encoding_programs;
static GLuint s_PBO = 0; // for readback with different strides static GLuint s_PBO = 0; // for readback with different strides
@ -133,16 +135,12 @@ static void CreatePrograms()
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb);
} }
static SHADER& GetOrCreateEncodingShader(u32 format) static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyFormat& format)
{ {
if (format >= NUM_ENCODING_PROGRAMS) auto iter = s_encoding_programs.find(format);
{ if (iter != s_encoding_programs.end())
PanicAlert("Unknown texture copy format: 0x%x\n", format); return iter->second;
return s_encodingPrograms[0];
}
if (s_encodingPrograms[format].glprogid == 0)
{
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::OpenGL); const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::OpenGL);
#if defined(_DEBUG) || defined(DEBUGFAST) #if defined(_DEBUG) || defined(DEBUGFAST)
@ -162,12 +160,12 @@ static SHADER& GetOrCreateEncodingShader(u32 format)
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
"}\n"; "}\n";
ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader); EncodingProgram program;
if (!ProgramShaderCache::CompileShader(program.program, VProgram, shader))
PanicAlert("Failed to compile texture encoding shader.");
s_encodingUniforms[format] = program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position");
glGetUniformLocation(s_encodingPrograms[format].glprogid, "position"); return s_encoding_programs.emplace(format, program).first->second;
}
return s_encodingPrograms[format];
} }
void Init() void Init()
@ -204,8 +202,9 @@ void Shutdown()
s_rgbToYuyvProgram.Destroy(); s_rgbToYuyvProgram.Destroy();
s_yuyvToRgbProgram.Destroy(); s_yuyvToRgbProgram.Destroy();
for (auto& program : s_encodingPrograms) for (auto& program : s_encoding_programs)
program.Destroy(); program.second.program.Destroy();
s_encoding_programs.clear();
s_srcTexture = 0; s_srcTexture = 0;
s_dstTexture = 0; s_dstTexture = 0;
@ -271,23 +270,24 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
} }
void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
g_renderer->ResetAPIState(); g_renderer->ResetAPIState();
SHADER& texconv_shader = GetOrCreateEncodingShader(format); EncodingProgram& texconv_shader = GetOrCreateEncodingShader(format);
texconv_shader.Bind(); texconv_shader.program.Bind();
glUniform4i(s_encodingUniforms[format], source.left, source.top, native_width, glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width,
bScaleByHalf ? 2 : 1); scale_by_half ? 2 : 1);
const GLuint read_texture = is_depth_copy ? FramebufferManager::ResolveAndGetDepthTarget(source) : const GLuint read_texture = is_depth_copy ?
FramebufferManager::ResolveAndGetRenderTarget(source); FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
FramebufferManager::ResolveAndGetRenderTarget(src_rect);
EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride, EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride,
bScaleByHalf > 0 && !is_depth_copy); scale_by_half && !is_depth_copy);
FramebufferManager::SetFramebuffer(0); FramebufferManager::SetFramebuffer(0);
g_renderer->RestoreAPIState(); g_renderer->RestoreAPIState();

View File

@ -7,6 +7,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLUtil.h" #include "Common/GL/GLUtil.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
namespace OGL namespace OGL
@ -24,9 +25,9 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
// returns size of the encoded data (in bytes) // returns size of the encoded data (in bytes)
void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source); bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half);
} }
} // namespace OGL } // namespace OGL

View File

@ -53,9 +53,9 @@ public:
TlutFormat format) override TlutFormat format) override
{ {
} }
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool scaleByHalf) override const EFBRectangle& src_rect, bool scale_by_half) override
{ {
EfbCopy::CopyEfb(); EfbCopy::CopyEfb();
} }

View File

@ -88,9 +88,9 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
m_texture_converter->ConvertTexture(entry, unconverted, m_render_pass, palette, format); m_texture_converter->ConvertTexture(entry, unconverted, m_render_pass, palette, format);
} }
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{ {
// Flush EFB pokes first, as they're expected to be included. // Flush EFB pokes first, as they're expected to be included.
FramebufferManager::GetInstance()->FlushEFBPokes(); FramebufferManager::GetInstance()->FlushEFBPokes();
@ -120,7 +120,7 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_
m_texture_converter->EncodeTextureToMemory(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, bytes_per_row, num_blocks_y, memory_stride,
is_depth_copy, is_intensity, scale_by_half, src_rect); is_depth_copy, src_rect, scale_by_half);
// Transition back to original state // Transition back to original state
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout); src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout);

View File

@ -59,9 +59,9 @@ public:
void ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* base_unconverted, void* palette, void ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* base_unconverted, void* palette,
TlutFormat format) override; TlutFormat format) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool is_intensity, bool scale_by_half) override; const EFBRectangle& src_rect, bool scale_by_half) override;
void CopyRectangleFromTexture(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect, void CopyRectangleFromTexture(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect); Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect);

View File

@ -57,11 +57,8 @@ TextureConverter::~TextureConverter()
if (m_encoding_render_framebuffer != VK_NULL_HANDLE) if (m_encoding_render_framebuffer != VK_NULL_HANDLE)
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr); vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr);
for (VkShaderModule shader : m_encoding_shaders) for (auto& it : m_encoding_shaders)
{ vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr);
if (shader != VK_NULL_HANDLE)
vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr);
}
for (const auto& it : m_decoding_pipelines) for (const auto& it : m_decoding_pipelines)
{ {
@ -89,12 +86,6 @@ bool TextureConverter::Initialize()
return false; return false;
} }
if (!CompileEncodingShaders())
{
PanicAlert("Failed to compile texture encoding shaders");
return false;
}
if (!CreateEncodingRenderPass()) if (!CreateEncodingRenderPass())
{ {
PanicAlert("Failed to create encode render pass"); PanicAlert("Failed to create encode render pass");
@ -221,15 +212,17 @@ void TextureConverter::ConvertTexture(TextureCache::TCacheEntry* dst_entry,
draw.EndRenderPass(); draw.EndRenderPass();
} }
void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr,
u32 native_width, u32 bytes_per_row, u32 num_blocks_y, const EFBCopyFormat& format, u32 native_width,
u32 memory_stride, bool is_depth_copy, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
bool is_intensity, int scale_by_half, bool is_depth_copy, const EFBRectangle& src_rect,
const EFBRectangle& src_rect) bool scale_by_half)
{ {
if (m_encoding_shaders[format] == VK_NULL_HANDLE) VkShaderModule shader = GetEncodingShader(format);
if (shader == VK_NULL_HANDLE)
{ {
ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format); ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u->%u", format.efb_format,
static_cast<u32>(format.copy_format));
return; return;
} }
@ -242,7 +235,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(), m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(),
VK_NULL_HANDLE, m_encoding_shaders[format]); VK_NULL_HANDLE, shader);
// Uniform - int4 of left,top,native_width,scale // Uniform - int4 of left,top,native_width,scale
s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast<s32>(native_width), s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast<s32>(native_width),
@ -681,24 +674,25 @@ bool TextureConverter::CompilePaletteConversionShaders()
m_palette_conversion_shaders[GX_TL_RGB5A3] != VK_NULL_HANDLE; m_palette_conversion_shaders[GX_TL_RGB5A3] != VK_NULL_HANDLE;
} }
bool TextureConverter::CompileEncodingShaders() VkShaderModule TextureConverter::CompileEncodingShader(const EFBCopyFormat& format)
{ {
// Texture encoding shaders const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan);
static const u32 texture_encoding_shader_formats[] = { VkShaderModule module = Util::CompileAndCreateFragmentShader(shader);
GX_TF_I4, GX_TF_I8, GX_TF_IA4, GX_TF_IA8, GX_TF_RGB565, GX_TF_RGB5A3, GX_TF_RGBA8, if (module == VK_NULL_HANDLE)
GX_CTF_R4, GX_CTF_RA4, GX_CTF_RA8, GX_CTF_A8, GX_CTF_R8, GX_CTF_G8, GX_CTF_B8, PanicAlert("Failed to compile texture encoding shader.");
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}; return module;
for (u32 format : texture_encoding_shader_formats)
{
const char* shader_source =
TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan);
m_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source);
if (m_encoding_shaders[format] == VK_NULL_HANDLE)
return false;
} }
return true; VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyFormat& format)
{
auto iter = m_encoding_shaders.find(format);
if (iter != m_encoding_shaders.end())
return iter->second;
VkShaderModule shader = CompileEncodingShader(format);
m_encoding_shaders.emplace(format, shader);
return shader;
} }
bool TextureConverter::CreateEncodingRenderPass() bool TextureConverter::CreateEncodingRenderPass()

View File

@ -35,10 +35,10 @@ public:
// Uses an encoding shader to copy src_texture to dest_ptr. // Uses an encoding shader to copy src_texture to dest_ptr.
// NOTE: Executes the current command buffer. // NOTE: Executes the current command buffer.
void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width, void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, const EFBCopyFormat& format,
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
bool is_depth_copy, bool is_intensity, int scale_by_half, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect,
const EFBRectangle& source); bool scale_by_half);
// Encodes texture to guest memory in XFB (YUYV) format. // Encodes texture to guest memory in XFB (YUYV) format.
void EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u32 dst_stride, u32 dst_height, void EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u32 dst_stride, u32 dst_height,
@ -55,7 +55,6 @@ public:
TlutFormat palette_format); TlutFormat palette_format);
private: private:
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;
@ -70,7 +69,9 @@ private:
bool CompilePaletteConversionShaders(); bool CompilePaletteConversionShaders();
bool CompileEncodingShaders(); VkShaderModule CompileEncodingShader(const EFBCopyFormat& format);
VkShaderModule GetEncodingShader(const EFBCopyFormat& format);
bool CreateEncodingRenderPass(); bool CreateEncodingRenderPass();
bool CreateEncodingTexture(); bool CreateEncodingTexture();
bool CreateEncodingDownloadTexture(); bool CreateEncodingDownloadTexture();
@ -102,7 +103,7 @@ private:
std::array<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_shaders = {}; std::array<VkShaderModule, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_shaders = {};
// Texture encoding - RGBA8->GX format in memory // Texture encoding - RGBA8->GX format in memory
std::array<VkShaderModule, NUM_TEXTURE_ENCODING_SHADERS> m_encoding_shaders = {}; std::map<EFBCopyFormat, VkShaderModule> m_encoding_shaders;
VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE; VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE;
std::unique_ptr<Texture2D> m_encoding_render_texture; std::unique_ptr<Texture2D> m_encoding_render_texture;
VkFramebuffer m_encoding_render_framebuffer = VK_NULL_HANDLE; VkFramebuffer m_encoding_render_framebuffer = VK_NULL_HANDLE;

View File

@ -969,7 +969,8 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFo
ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f; ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f;
ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f; ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f;
unsigned int cbufid = -1; unsigned int cbufid = -1;
bool efbHasAlpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; u32 srcFormat = bpmem.zcontrol.pixel_format;
bool efbHasAlpha = srcFormat == PEControl::RGBA6_Z24;
if (is_depth_copy) if (is_depth_copy)
{ {
@ -1278,8 +1279,9 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFo
if (copy_to_ram) if (copy_to_ram)
{ {
CopyEFB(dst, dstFormat, tex_w, bytes_per_row, num_blocks_y, dstStride, is_depth_copy, srcRect, EFBCopyFormat format(srcFormat, static_cast<TextureFormat>(dstFormat));
isIntensity, scaleByHalf); CopyEFB(dst, format, tex_w, bytes_per_row, num_blocks_y, dstStride, is_depth_copy, srcRect,
scaleByHalf);
} }
else else
{ {

View File

@ -154,9 +154,9 @@ public:
virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0; virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0;
virtual void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, virtual void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
bool isIntensity, bool scaleByHalf) = 0; const EFBRectangle& src_rect, bool scale_by_half) = 0;
virtual bool CompileShaders() = 0; virtual bool CompileShaders() = 0;
virtual void DeleteShaders() = 0; virtual void DeleteShaders() = 0;