Merge pull request #5202 from stenzek/efb-copy-source-format
TextureConversionShader: Consider source format of EFB for EFB2RAM
This commit is contained in:
commit
29344cb5ff
|
@ -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, ¶ms, 0, 0);
|
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 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,61 +168,27 @@ 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())
|
||||||
|
return iter->second;
|
||||||
|
|
||||||
ComboMap::iterator it = m_staticShaders.find(key);
|
D3DBlob* bytecode = nullptr;
|
||||||
if (it == m_staticShaders.end())
|
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
|
||||||
|
if (!D3D::CompilePixelShader(shader, &bytecode))
|
||||||
{
|
{
|
||||||
INFO_LOG(VIDEO,
|
PanicAlert("Failed to compile texture encoding shader.");
|
||||||
"Compiling efb encoding shader for dstFormat 0x%X, is_depth_copy %d, isIntensity "
|
m_encoding_shaders[format] = nullptr;
|
||||||
"%d, scaleByHalf %d",
|
return nullptr;
|
||||||
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;
|
|
||||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
|
|
||||||
if (!D3D::CompilePixelShader(shader, &bytecode))
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, is_depth_copy %d, isIntensity %d, "
|
|
||||||
"scaleByHalf %d failed to compile",
|
|
||||||
dstFormat, is_depth_copy, isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
|
|
||||||
m_staticShaders[key] = nullptr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11PixelShader* newShader;
|
|
||||||
HRESULT hr =
|
|
||||||
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
|
|
||||||
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
|
|
||||||
|
|
||||||
char debugName[255] = {};
|
|
||||||
sprintf_s(debugName,
|
|
||||||
"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;
|
ID3D11PixelShader* newShader;
|
||||||
|
HRESULT hr =
|
||||||
|
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
|
||||||
|
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
|
||||||
|
|
||||||
|
m_encoding_shaders.emplace(format, newShader);
|
||||||
|
return newShader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[] =
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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())
|
||||||
|
return iter->second;
|
||||||
|
|
||||||
ComboMap::iterator it = m_static_shaders_map.find(key);
|
ID3DBlob* bytecode = nullptr;
|
||||||
if (it == m_static_shaders_map.end())
|
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
|
||||||
|
if (!D3D::CompilePixelShader(shader, &bytecode))
|
||||||
{
|
{
|
||||||
INFO_LOG(VIDEO, "Compiling efb encoding shader for dst_format 0x%X, is_depth_copy %d, "
|
PanicAlert("Failed to compile texture encoding shader.");
|
||||||
"is_intensity %d, scale_by_half %d",
|
m_encoding_shaders[format] = {};
|
||||||
dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0);
|
return {};
|
||||||
|
|
||||||
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;
|
|
||||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D);
|
|
||||||
if (!D3D::CompilePixelShader(shader, &bytecode))
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "EFB encoder shader for dst_format 0x%X, is_depth_copy %d, is_intensity %d, "
|
|
||||||
"scale_by_half %d failed to compile",
|
|
||||||
dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0);
|
|
||||||
m_static_shaders_blobs[key] = {};
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()};
|
|
||||||
|
|
||||||
it = m_static_shaders_map.emplace(key, new_shader).first;
|
|
||||||
|
|
||||||
// Keep track of the ID3DBlobs, so we can free them upon shutdown.
|
|
||||||
m_static_shaders_blobs.push_back(bytecode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->second;
|
D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()};
|
||||||
|
m_encoding_shaders.emplace(format, new_shader);
|
||||||
|
|
||||||
|
// Keep track of the ID3DBlobs, so we can free them upon shutdown.
|
||||||
|
m_shader_blobs.push_back(bytecode);
|
||||||
|
|
||||||
|
return new_shader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[] =
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,41 +135,37 @@ 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)
|
||||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
|
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
|
||||||
{
|
{
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
std::string filename =
|
std::string filename =
|
||||||
StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||||
|
|
||||||
SaveData(filename, shader);
|
SaveData(filename, shader);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* VProgram = "void main()\n"
|
const char* VProgram = "void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
|
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
|
||||||
" 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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "VideoCommon/TextureConversionShader.h"
|
#include "VideoCommon/TextureConversionShader.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -57,11 +58,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 +87,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 +213,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,17 +236,19 @@ 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),
|
||||||
scale_by_half ? 2 : 1};
|
scale_by_half ? 2 : 1};
|
||||||
draw.SetPushConstants(position_uniform, sizeof(position_uniform));
|
draw.SetPushConstants(position_uniform, sizeof(position_uniform));
|
||||||
|
|
||||||
// Doesn't make sense to linear filter depth values
|
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
||||||
draw.SetPSSampler(0, src_texture, (scale_by_half && !is_depth_copy) ?
|
// TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will
|
||||||
g_object_cache->GetLinearSampler() :
|
// need more complex down filtering to average all pixels and produce the correct result.
|
||||||
g_object_cache->GetPointSampler());
|
bool linear_filter = (scale_by_half && !is_depth_copy) || g_ActiveConfig.iEFBScale != SCALE_1X;
|
||||||
|
draw.SetPSSampler(0, src_texture, linear_filter ? g_object_cache->GetLinearSampler() :
|
||||||
|
g_object_cache->GetPointSampler());
|
||||||
|
|
||||||
u32 render_width = bytes_per_row / sizeof(u32);
|
u32 render_width = bytes_per_row / sizeof(u32);
|
||||||
u32 render_height = num_blocks_y;
|
u32 render_height = num_blocks_y;
|
||||||
|
@ -681,24 +677,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};
|
|
||||||
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;
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/TextureConversionShader.h"
|
#include "VideoCommon/TextureConversionShader.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
|
||||||
#define WRITE p += sprintf
|
#define WRITE p += sprintf
|
||||||
|
@ -79,6 +78,11 @@ u16 GetEncodedSampleCount(u32 format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool EFBFormatHasAlpha(u32 format)
|
||||||
|
{
|
||||||
|
return format == PEControl::RGBA6_Z24;
|
||||||
|
}
|
||||||
|
|
||||||
// block dimensions : widthStride, heightStride
|
// block dimensions : widthStride, heightStride
|
||||||
// texture dims : width, height, x offset, y offset
|
// texture dims : width, height, x offset, y offset
|
||||||
static void WriteSwizzler(char*& p, u32 format, APIType ApiType)
|
static void WriteSwizzler(char*& p, u32 format, APIType ApiType)
|
||||||
|
@ -162,7 +166,7 @@ static void WriteSwizzler(char*& p, u32 format, APIType ApiType)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset,
|
static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset,
|
||||||
APIType ApiType, bool depth = false)
|
APIType ApiType, const EFBCopyFormat& format, bool depth)
|
||||||
{
|
{
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
|
@ -181,6 +185,25 @@ static void WriteSampleColor(char*& p, const char* colorComp, const char* dest,
|
||||||
if (depth)
|
if (depth)
|
||||||
WRITE(p, " %s = 1.0 - %s;\n", dest, dest);
|
WRITE(p, " %s = 1.0 - %s;\n", dest, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Truncate 8-bits to 5/6-bits per channel.
|
||||||
|
switch (format.efb_format)
|
||||||
|
{
|
||||||
|
case PEControl::RGBA6_Z24:
|
||||||
|
WRITE(p, " %s = floor(%s * 63.0) / 63.0;\n", dest, dest);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PEControl::RGB565_Z16:
|
||||||
|
WRITE(
|
||||||
|
p,
|
||||||
|
" %s = floor(%s * float4(31.0, 63.0, 31.0, 1.0).%s) / float4(31.0, 63.0, 31.0, 1.0).%s;\n",
|
||||||
|
dest, dest, colorComp, colorComp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha channel is set to 1 in the copy if the EFB does not have an alpha channel.
|
||||||
|
if (std::strchr(colorComp, 'a') && !EFBFormatHasAlpha(format.efb_format))
|
||||||
|
WRITE(p, " %s.a = 1.0;\n", dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteColorToIntensity(char*& p, const char* src, const char* dest)
|
static void WriteColorToIntensity(char*& p, const char* src, const char* dest)
|
||||||
|
@ -206,21 +229,21 @@ static void WriteEncoderEnd(char*& p)
|
||||||
IntensityConstantAdded = false;
|
IntensityConstantAdded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteI8Encoder(char*& p, APIType ApiType)
|
static void WriteI8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_I8, ApiType);
|
WriteSwizzler(p, GX_TF_I8, ApiType);
|
||||||
WRITE(p, " float3 texSample;\n");
|
WRITE(p, " float3 texSample;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 0, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.b");
|
WriteColorToIntensity(p, "texSample", "ocol0.b");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 1, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.g");
|
WriteColorToIntensity(p, "texSample", "ocol0.g");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 2, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 2, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.r");
|
WriteColorToIntensity(p, "texSample", "ocol0.r");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 3, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 3, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.a");
|
WriteColorToIntensity(p, "texSample", "ocol0.a");
|
||||||
|
|
||||||
WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity
|
WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity
|
||||||
|
@ -228,35 +251,35 @@ static void WriteI8Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteI4Encoder(char*& p, APIType ApiType)
|
static void WriteI4Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_I4, ApiType);
|
WriteSwizzler(p, GX_TF_I4, ApiType);
|
||||||
WRITE(p, " float3 texSample;\n");
|
WRITE(p, " float3 texSample;\n");
|
||||||
WRITE(p, " float4 color0;\n");
|
WRITE(p, " float4 color0;\n");
|
||||||
WRITE(p, " float4 color1;\n");
|
WRITE(p, " float4 color1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 0, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color0.b");
|
WriteColorToIntensity(p, "texSample", "color0.b");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 1, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color1.b");
|
WriteColorToIntensity(p, "texSample", "color1.b");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 2, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 2, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color0.g");
|
WriteColorToIntensity(p, "texSample", "color0.g");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 3, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 3, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color1.g");
|
WriteColorToIntensity(p, "texSample", "color1.g");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 4, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 4, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color0.r");
|
WriteColorToIntensity(p, "texSample", "color0.r");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 5, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 5, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color1.r");
|
WriteColorToIntensity(p, "texSample", "color1.r");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 6, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 6, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color0.a");
|
WriteColorToIntensity(p, "texSample", "color0.a");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "texSample", 7, ApiType);
|
WriteSampleColor(p, "rgb", "texSample", 7, ApiType, format, false);
|
||||||
WriteColorToIntensity(p, "texSample", "color1.a");
|
WriteColorToIntensity(p, "texSample", "color1.a");
|
||||||
|
|
||||||
WRITE(p, " color0.rgba += IntensityConst.aaaa;\n");
|
WRITE(p, " color0.rgba += IntensityConst.aaaa;\n");
|
||||||
|
@ -269,16 +292,16 @@ static void WriteI4Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteIA8Encoder(char*& p, APIType ApiType)
|
static void WriteIA8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_IA8, ApiType);
|
WriteSwizzler(p, GX_TF_IA8, ApiType);
|
||||||
WRITE(p, " float4 texSample;\n");
|
WRITE(p, " float4 texSample;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false);
|
||||||
WRITE(p, " ocol0.b = texSample.a;\n");
|
WRITE(p, " ocol0.b = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.g");
|
WriteColorToIntensity(p, "texSample", "ocol0.g");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false);
|
||||||
WRITE(p, " ocol0.r = texSample.a;\n");
|
WRITE(p, " ocol0.r = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "ocol0.a");
|
WriteColorToIntensity(p, "texSample", "ocol0.a");
|
||||||
|
|
||||||
|
@ -287,26 +310,26 @@ static void WriteIA8Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteIA4Encoder(char*& p, APIType ApiType)
|
static void WriteIA4Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_IA4, ApiType);
|
WriteSwizzler(p, GX_TF_IA4, ApiType);
|
||||||
WRITE(p, " float4 texSample;\n");
|
WRITE(p, " float4 texSample;\n");
|
||||||
WRITE(p, " float4 color0;\n");
|
WRITE(p, " float4 color0;\n");
|
||||||
WRITE(p, " float4 color1;\n");
|
WRITE(p, " float4 color1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false);
|
||||||
WRITE(p, " color0.b = texSample.a;\n");
|
WRITE(p, " color0.b = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "color1.b");
|
WriteColorToIntensity(p, "texSample", "color1.b");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false);
|
||||||
WRITE(p, " color0.g = texSample.a;\n");
|
WRITE(p, " color0.g = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "color1.g");
|
WriteColorToIntensity(p, "texSample", "color1.g");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 2, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 2, ApiType, format, false);
|
||||||
WRITE(p, " color0.r = texSample.a;\n");
|
WRITE(p, " color0.r = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "color1.r");
|
WriteColorToIntensity(p, "texSample", "color1.r");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 3, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 3, ApiType, format, false);
|
||||||
WRITE(p, " color0.a = texSample.a;\n");
|
WRITE(p, " color0.a = texSample.a;\n");
|
||||||
WriteColorToIntensity(p, "texSample", "color1.a");
|
WriteColorToIntensity(p, "texSample", "color1.a");
|
||||||
|
|
||||||
|
@ -319,12 +342,12 @@ static void WriteIA4Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteRGB565Encoder(char*& p, APIType ApiType)
|
static void WriteRGB565Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_RGB565, ApiType);
|
WriteSwizzler(p, GX_TF_RGB565, ApiType);
|
||||||
|
|
||||||
WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType);
|
WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType, format, false);
|
||||||
WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType);
|
WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType, format, false);
|
||||||
WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n");
|
WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n");
|
||||||
WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n");
|
WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n");
|
||||||
WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n");
|
WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n");
|
||||||
|
@ -342,7 +365,7 @@ static void WriteRGB565Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteRGB5A3Encoder(char*& p, APIType ApiType)
|
static void WriteRGB5A3Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_RGB5A3, ApiType);
|
WriteSwizzler(p, GX_TF_RGB5A3, ApiType);
|
||||||
|
|
||||||
|
@ -351,7 +374,7 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType)
|
||||||
WRITE(p, " float gUpper;\n");
|
WRITE(p, " float gUpper;\n");
|
||||||
WRITE(p, " float gLower;\n");
|
WRITE(p, " float gLower;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false);
|
||||||
|
|
||||||
// 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits
|
// 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits
|
||||||
WRITE(p, "if(texSample.a > 0.878f) {\n");
|
WRITE(p, "if(texSample.a > 0.878f) {\n");
|
||||||
|
@ -377,7 +400,8 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType)
|
||||||
|
|
||||||
WRITE(p, "}\n");
|
WRITE(p, "}\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false);
|
||||||
|
WRITE(p, " texSample.a = 1.0;\n");
|
||||||
|
|
||||||
WRITE(p, "if(texSample.a > 0.878f) {\n");
|
WRITE(p, "if(texSample.a > 0.878f) {\n");
|
||||||
|
|
||||||
|
@ -406,7 +430,7 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteRGBA8Encoder(char*& p, APIType ApiType)
|
static void WriteRGBA8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_RGBA8, ApiType);
|
WriteSwizzler(p, GX_TF_RGBA8, ApiType);
|
||||||
|
|
||||||
|
@ -414,13 +438,13 @@ static void WriteRGBA8Encoder(char*& p, APIType ApiType)
|
||||||
WRITE(p, " float4 color0;\n");
|
WRITE(p, " float4 color0;\n");
|
||||||
WRITE(p, " float4 color1;\n");
|
WRITE(p, " float4 color1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 0, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false);
|
||||||
WRITE(p, " color0.b = texSample.a;\n");
|
WRITE(p, " color0.b = texSample.a;\n");
|
||||||
WRITE(p, " color0.g = texSample.r;\n");
|
WRITE(p, " color0.g = texSample.r;\n");
|
||||||
WRITE(p, " color1.b = texSample.g;\n");
|
WRITE(p, " color1.b = texSample.g;\n");
|
||||||
WRITE(p, " color1.g = texSample.b;\n");
|
WRITE(p, " color1.g = texSample.b;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "rgba", "texSample", 1, ApiType);
|
WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false);
|
||||||
WRITE(p, " color0.r = texSample.a;\n");
|
WRITE(p, " color0.r = texSample.a;\n");
|
||||||
WRITE(p, " color0.a = texSample.r;\n");
|
WRITE(p, " color0.a = texSample.r;\n");
|
||||||
WRITE(p, " color1.r = texSample.g;\n");
|
WRITE(p, " color1.r = texSample.g;\n");
|
||||||
|
@ -431,20 +455,21 @@ static void WriteRGBA8Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, bool depth = false)
|
static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyFormat& format,
|
||||||
|
bool depth)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_R4, ApiType);
|
WriteSwizzler(p, GX_CTF_R4, ApiType);
|
||||||
WRITE(p, " float4 color0;\n");
|
WRITE(p, " float4 color0;\n");
|
||||||
WRITE(p, " float4 color1;\n");
|
WRITE(p, " float4 color1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "color0.b", 0, ApiType, depth);
|
WriteSampleColor(p, comp, "color0.b", 0, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color1.b", 1, ApiType, depth);
|
WriteSampleColor(p, comp, "color1.b", 1, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color0.g", 2, ApiType, depth);
|
WriteSampleColor(p, comp, "color0.g", 2, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color1.g", 3, ApiType, depth);
|
WriteSampleColor(p, comp, "color1.g", 3, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color0.r", 4, ApiType, depth);
|
WriteSampleColor(p, comp, "color0.r", 4, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color1.r", 5, ApiType, depth);
|
WriteSampleColor(p, comp, "color1.r", 5, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color0.a", 6, ApiType, depth);
|
WriteSampleColor(p, comp, "color0.a", 6, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "color1.a", 7, ApiType, depth);
|
WriteSampleColor(p, comp, "color1.a", 7, ApiType, format, depth);
|
||||||
|
|
||||||
WriteToBitDepth(p, 4, "color0", "color0");
|
WriteToBitDepth(p, 4, "color0", "color0");
|
||||||
WriteToBitDepth(p, 4, "color1", "color1");
|
WriteToBitDepth(p, 4, "color1", "color1");
|
||||||
|
@ -453,38 +478,40 @@ static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, bool dep
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, bool depth = false)
|
static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyFormat& format,
|
||||||
|
bool depth)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_R8, ApiType);
|
WriteSwizzler(p, GX_CTF_R8, ApiType);
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, depth);
|
WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, depth);
|
WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, depth);
|
WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, format, depth);
|
||||||
WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, depth);
|
WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, format, depth);
|
||||||
|
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType)
|
static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType,
|
||||||
|
const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_RA4, ApiType);
|
WriteSwizzler(p, GX_CTF_RA4, ApiType);
|
||||||
WRITE(p, " float2 texSample;\n");
|
WRITE(p, " float2 texSample;\n");
|
||||||
WRITE(p, " float4 color0;\n");
|
WRITE(p, " float4 color0;\n");
|
||||||
WRITE(p, " float4 color1;\n");
|
WRITE(p, " float4 color1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "texSample", 0, ApiType);
|
WriteSampleColor(p, comp, "texSample", 0, ApiType, format, false);
|
||||||
WRITE(p, " color0.b = texSample.x;\n");
|
WRITE(p, " color0.b = texSample.x;\n");
|
||||||
WRITE(p, " color1.b = texSample.y;\n");
|
WRITE(p, " color1.b = texSample.y;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "texSample", 1, ApiType);
|
WriteSampleColor(p, comp, "texSample", 1, ApiType, format, false);
|
||||||
WRITE(p, " color0.g = texSample.x;\n");
|
WRITE(p, " color0.g = texSample.x;\n");
|
||||||
WRITE(p, " color1.g = texSample.y;\n");
|
WRITE(p, " color1.g = texSample.y;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "texSample", 2, ApiType);
|
WriteSampleColor(p, comp, "texSample", 2, ApiType, format, false);
|
||||||
WRITE(p, " color0.r = texSample.x;\n");
|
WRITE(p, " color0.r = texSample.x;\n");
|
||||||
WRITE(p, " color1.r = texSample.y;\n");
|
WRITE(p, " color1.r = texSample.y;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "texSample", 3, ApiType);
|
WriteSampleColor(p, comp, "texSample", 3, ApiType, format, false);
|
||||||
WRITE(p, " color0.a = texSample.x;\n");
|
WRITE(p, " color0.a = texSample.x;\n");
|
||||||
WRITE(p, " color1.a = texSample.y;\n");
|
WRITE(p, " color1.a = texSample.y;\n");
|
||||||
|
|
||||||
|
@ -495,38 +522,40 @@ static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType)
|
static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType,
|
||||||
|
const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_RA8, ApiType);
|
WriteSwizzler(p, GX_CTF_RA8, ApiType);
|
||||||
|
|
||||||
WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType);
|
WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType, format, false);
|
||||||
WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType);
|
WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType, format, false);
|
||||||
|
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType)
|
static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType,
|
||||||
|
const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_Z8M, ApiType);
|
WriteSwizzler(p, GX_CTF_Z8M, ApiType);
|
||||||
|
|
||||||
WRITE(p, " float depth;\n");
|
WRITE(p, " float depth;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 0, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 0, ApiType, format, true);
|
||||||
WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier);
|
WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier);
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 1, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 1, ApiType, format, true);
|
||||||
WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier);
|
WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier);
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 2, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 2, ApiType, format, true);
|
||||||
WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier);
|
WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier);
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 3, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 3, ApiType, format, true);
|
||||||
WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier);
|
WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier);
|
||||||
|
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteZ16Encoder(char*& p, APIType ApiType)
|
static void WriteZ16Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_Z16, ApiType);
|
WriteSwizzler(p, GX_TF_Z16, ApiType);
|
||||||
|
|
||||||
|
@ -535,7 +564,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType)
|
||||||
|
|
||||||
// byte order is reversed
|
// byte order is reversed
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 0, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 0, ApiType, format, true);
|
||||||
|
|
||||||
WRITE(p, " depth *= 16777216.0;\n");
|
WRITE(p, " depth *= 16777216.0;\n");
|
||||||
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
||||||
|
@ -545,7 +574,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType)
|
||||||
WRITE(p, " ocol0.b = expanded.g / 255.0;\n");
|
WRITE(p, " ocol0.b = expanded.g / 255.0;\n");
|
||||||
WRITE(p, " ocol0.g = expanded.r / 255.0;\n");
|
WRITE(p, " ocol0.g = expanded.r / 255.0;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 1, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 1, ApiType, format, true);
|
||||||
|
|
||||||
WRITE(p, " depth *= 16777216.0;\n");
|
WRITE(p, " depth *= 16777216.0;\n");
|
||||||
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
||||||
|
@ -558,7 +587,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteZ16LEncoder(char*& p, APIType ApiType)
|
static void WriteZ16LEncoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_CTF_Z16L, ApiType);
|
WriteSwizzler(p, GX_CTF_Z16L, ApiType);
|
||||||
|
|
||||||
|
@ -567,7 +596,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType)
|
||||||
|
|
||||||
// byte order is reversed
|
// byte order is reversed
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 0, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 0, ApiType, format, true);
|
||||||
|
|
||||||
WRITE(p, " depth *= 16777216.0;\n");
|
WRITE(p, " depth *= 16777216.0;\n");
|
||||||
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
||||||
|
@ -579,7 +608,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType)
|
||||||
WRITE(p, " ocol0.b = expanded.b / 255.0;\n");
|
WRITE(p, " ocol0.b = expanded.b / 255.0;\n");
|
||||||
WRITE(p, " ocol0.g = expanded.g / 255.0;\n");
|
WRITE(p, " ocol0.g = expanded.g / 255.0;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth", 1, ApiType, true);
|
WriteSampleColor(p, "r", "depth", 1, ApiType, format, true);
|
||||||
|
|
||||||
WRITE(p, " depth *= 16777216.0;\n");
|
WRITE(p, " depth *= 16777216.0;\n");
|
||||||
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n");
|
||||||
|
@ -594,7 +623,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteZ24Encoder(char*& p, APIType ApiType)
|
static void WriteZ24Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format)
|
||||||
{
|
{
|
||||||
WriteSwizzler(p, GX_TF_Z24X8, ApiType);
|
WriteSwizzler(p, GX_TF_Z24X8, ApiType);
|
||||||
|
|
||||||
|
@ -603,8 +632,8 @@ static void WriteZ24Encoder(char*& p, APIType ApiType)
|
||||||
WRITE(p, " float3 expanded0;\n");
|
WRITE(p, " float3 expanded0;\n");
|
||||||
WRITE(p, " float3 expanded1;\n");
|
WRITE(p, " float3 expanded1;\n");
|
||||||
|
|
||||||
WriteSampleColor(p, "r", "depth0", 0, ApiType, true);
|
WriteSampleColor(p, "r", "depth0", 0, ApiType, format, true);
|
||||||
WriteSampleColor(p, "r", "depth1", 1, ApiType, true);
|
WriteSampleColor(p, "r", "depth1", 1, ApiType, format, true);
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
|
@ -634,87 +663,87 @@ static void WriteZ24Encoder(char*& p, APIType ApiType)
|
||||||
WriteEncoderEnd(p);
|
WriteEncoderEnd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GenerateEncodingShader(u32 format, APIType ApiType)
|
const char* GenerateEncodingShader(const EFBCopyFormat& format, APIType api_type)
|
||||||
{
|
{
|
||||||
text[sizeof(text) - 1] = 0x7C; // canary
|
text[sizeof(text) - 1] = 0x7C; // canary
|
||||||
|
|
||||||
char* p = text;
|
char* p = text;
|
||||||
|
|
||||||
switch (format)
|
switch (format.copy_format)
|
||||||
{
|
{
|
||||||
case GX_TF_I4:
|
case GX_TF_I4:
|
||||||
WriteI4Encoder(p, ApiType);
|
WriteI4Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_I8:
|
case GX_TF_I8:
|
||||||
WriteI8Encoder(p, ApiType);
|
WriteI8Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_IA4:
|
case GX_TF_IA4:
|
||||||
WriteIA4Encoder(p, ApiType);
|
WriteIA4Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_IA8:
|
case GX_TF_IA8:
|
||||||
WriteIA8Encoder(p, ApiType);
|
WriteIA8Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_RGB565:
|
case GX_TF_RGB565:
|
||||||
WriteRGB565Encoder(p, ApiType);
|
WriteRGB565Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_RGB5A3:
|
case GX_TF_RGB5A3:
|
||||||
WriteRGB5A3Encoder(p, ApiType);
|
WriteRGB5A3Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_RGBA8:
|
case GX_TF_RGBA8:
|
||||||
WriteRGBA8Encoder(p, ApiType);
|
WriteRGBA8Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_R4:
|
case GX_CTF_R4:
|
||||||
WriteC4Encoder(p, "r", ApiType);
|
WriteC4Encoder(p, "r", api_type, format, false);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_RA4:
|
case GX_CTF_RA4:
|
||||||
WriteCC4Encoder(p, "ar", ApiType);
|
WriteCC4Encoder(p, "ar", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_RA8:
|
case GX_CTF_RA8:
|
||||||
WriteCC8Encoder(p, "ar", ApiType);
|
WriteCC8Encoder(p, "ar", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_A8:
|
case GX_CTF_A8:
|
||||||
WriteC8Encoder(p, "a", ApiType);
|
WriteC8Encoder(p, "a", api_type, format, false);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_R8:
|
case GX_CTF_R8:
|
||||||
WriteC8Encoder(p, "r", ApiType);
|
WriteC8Encoder(p, "r", api_type, format, false);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_G8:
|
case GX_CTF_G8:
|
||||||
WriteC8Encoder(p, "g", ApiType);
|
WriteC8Encoder(p, "g", api_type, format, false);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_B8:
|
case GX_CTF_B8:
|
||||||
WriteC8Encoder(p, "b", ApiType);
|
WriteC8Encoder(p, "b", api_type, format, false);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_RG8:
|
case GX_CTF_RG8:
|
||||||
WriteCC8Encoder(p, "rg", ApiType);
|
WriteCC8Encoder(p, "rg", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_GB8:
|
case GX_CTF_GB8:
|
||||||
WriteCC8Encoder(p, "gb", ApiType);
|
WriteCC8Encoder(p, "gb", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z8H:
|
case GX_CTF_Z8H:
|
||||||
case GX_TF_Z8:
|
case GX_TF_Z8:
|
||||||
WriteC8Encoder(p, "r", ApiType, true);
|
WriteC8Encoder(p, "r", api_type, format, true);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z16R:
|
case GX_CTF_Z16R:
|
||||||
case GX_TF_Z16:
|
case GX_TF_Z16:
|
||||||
WriteZ16Encoder(p, ApiType);
|
WriteZ16Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_TF_Z24X8:
|
case GX_TF_Z24X8:
|
||||||
WriteZ24Encoder(p, ApiType);
|
WriteZ24Encoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z4:
|
case GX_CTF_Z4:
|
||||||
WriteC4Encoder(p, "r", ApiType, true);
|
WriteC4Encoder(p, "r", api_type, format, true);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z8M:
|
case GX_CTF_Z8M:
|
||||||
WriteZ8Encoder(p, "256.0", ApiType);
|
WriteZ8Encoder(p, "256.0", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z8L:
|
case GX_CTF_Z8L:
|
||||||
WriteZ8Encoder(p, "65536.0", ApiType);
|
WriteZ8Encoder(p, "65536.0", api_type, format);
|
||||||
break;
|
break;
|
||||||
case GX_CTF_Z16L:
|
case GX_CTF_Z16L:
|
||||||
WriteZ16LEncoder(p, ApiType);
|
WriteZ16LEncoder(p, api_type, format);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unknown texture copy format: 0x%x\n", format);
|
PanicAlert("Unknown texture copy format: 0x%x\n", static_cast<u32>(format.copy_format));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,9 +1248,9 @@ static const std::array<u32, BUFFER_FORMAT_COUNT> s_buffer_bytes_per_texel = {{
|
||||||
8, // BUFFER_FORMAT_R32G32_UINT
|
8, // BUFFER_FORMAT_R32G32_UINT
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const DecodingShaderInfo* GetDecodingShaderInfo(u32 format)
|
const DecodingShaderInfo* GetDecodingShaderInfo(TextureFormat format)
|
||||||
{
|
{
|
||||||
auto iter = s_decoding_shader_info.find(static_cast<TextureFormat>(format));
|
auto iter = s_decoding_shader_info.find(format);
|
||||||
return iter != s_decoding_shader_info.end() ? &iter->second : nullptr;
|
return iter != s_decoding_shader_info.end() ? &iter->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1240,7 +1269,8 @@ std::pair<u32, u32> GetDispatchCount(const DecodingShaderInfo* info, u32 width,
|
||||||
(height + (info->group_size_y - 1)) / info->group_size_y};
|
(height + (info->group_size_y - 1)) / info->group_size_y};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateDecodingShader(u32 format, u32 palette_format, APIType api_type)
|
std::string GenerateDecodingShader(TextureFormat format, TlutFormat palette_format,
|
||||||
|
APIType api_type)
|
||||||
{
|
{
|
||||||
const DecodingShaderInfo* info = GetDecodingShaderInfo(format);
|
const DecodingShaderInfo* info = GetDecodingShaderInfo(format);
|
||||||
if (!info)
|
if (!info)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
|
|
||||||
enum class APIType;
|
enum class APIType;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ namespace TextureConversionShader
|
||||||
{
|
{
|
||||||
u16 GetEncodedSampleCount(u32 format);
|
u16 GetEncodedSampleCount(u32 format);
|
||||||
|
|
||||||
const char* GenerateEncodingShader(u32 format, APIType ApiType);
|
const char* GenerateEncodingShader(const EFBCopyFormat& format, APIType ApiType);
|
||||||
|
|
||||||
// View format of the input data to the texture decoding shader.
|
// View format of the input data to the texture decoding shader.
|
||||||
enum BufferFormat
|
enum BufferFormat
|
||||||
|
@ -39,7 +40,7 @@ struct DecodingShaderInfo
|
||||||
|
|
||||||
// Obtain shader information for the specified texture format.
|
// Obtain shader information for the specified texture format.
|
||||||
// If this format does not have a shader written for it, returns nullptr.
|
// If this format does not have a shader written for it, returns nullptr.
|
||||||
const DecodingShaderInfo* GetDecodingShaderInfo(u32 format);
|
const DecodingShaderInfo* GetDecodingShaderInfo(TextureFormat format);
|
||||||
|
|
||||||
// Determine how many bytes there are in each element of the texel buffer.
|
// Determine how many bytes there are in each element of the texel buffer.
|
||||||
// Needed for alignment and stride calculations.
|
// Needed for alignment and stride calculations.
|
||||||
|
@ -50,6 +51,7 @@ u32 GetBytesPerBufferElement(BufferFormat buffer_format);
|
||||||
std::pair<u32, u32> GetDispatchCount(const DecodingShaderInfo* info, u32 width, u32 height);
|
std::pair<u32, u32> GetDispatchCount(const DecodingShaderInfo* info, u32 width, u32 height);
|
||||||
|
|
||||||
// Returns the GLSL string containing the texture decoding shader for the specified format.
|
// Returns the GLSL string containing the texture decoding shader for the specified format.
|
||||||
std::string GenerateDecodingShader(u32 format, u32 palette_format, APIType api_type);
|
std::string GenerateDecodingShader(TextureFormat format, TlutFormat palette_format,
|
||||||
|
APIType api_type);
|
||||||
|
|
||||||
} // namespace TextureConversionShader
|
} // namespace TextureConversionShader
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -67,6 +68,22 @@ enum TlutFormat
|
||||||
GX_TL_RGB5A3 = 0x2,
|
GX_TL_RGB5A3 = 0x2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EFBCopyFormat
|
||||||
|
{
|
||||||
|
EFBCopyFormat(u32 efb_format_, TextureFormat copy_format_)
|
||||||
|
: efb_format(efb_format_), copy_format(copy_format_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const EFBCopyFormat& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(efb_format, copy_format) < std::tie(rhs.efb_format, rhs.copy_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 efb_format;
|
||||||
|
TextureFormat copy_format;
|
||||||
|
};
|
||||||
|
|
||||||
int TexDecoder_GetTexelSizeInNibbles(int format);
|
int TexDecoder_GetTexelSizeInNibbles(int format);
|
||||||
int TexDecoder_GetTextureSizeInBytes(int width, int height, int format);
|
int TexDecoder_GetTextureSizeInBytes(int width, int height, int format);
|
||||||
int TexDecoder_GetBlockWidthInTexels(u32 format);
|
int TexDecoder_GetBlockWidthInTexels(u32 format);
|
||||||
|
|
Loading…
Reference in New Issue