mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Implement EFB copy filter and gamma in hardware backends
Also makes y_scale a dynamic parameter for EFB copies, as it doesn't make sense to keep it as part of the uid, otherwise we're generating redundant shaders.
This commit is contained in:
@ -31,7 +31,11 @@ struct EFBEncodeParams
|
||||
u32 DestWidth;
|
||||
u32 ScaleFactor;
|
||||
float y_scale;
|
||||
u32 padding[3];
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
s32 filter_coefficients[3];
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
PSTextureEncoder::PSTextureEncoder()
|
||||
@ -66,9 +70,11 @@ void PSTextureEncoder::Shutdown()
|
||||
SAFE_RELEASE(m_encode_params);
|
||||
}
|
||||
|
||||
void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
void PSTextureEncoder::Encode(
|
||||
u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
|
||||
u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half, float y_scale, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
// Resolve MSAA targets before copying.
|
||||
// FIXME: Instead of resolving EFB, it would be better to pick out a
|
||||
@ -101,7 +107,13 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||
encode_params.SrcTop = src_rect.top;
|
||||
encode_params.DestWidth = native_width;
|
||||
encode_params.ScaleFactor = scale_by_half ? 2 : 1;
|
||||
encode_params.y_scale = params.y_scale;
|
||||
encode_params.y_scale = y_scale;
|
||||
encode_params.gamma_rcp = 1.0f / gamma;
|
||||
encode_params.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
encode_params.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 0.0f;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
encode_params.filter_coefficients[i] = filter_coefficients[i];
|
||||
|
||||
D3D::context->UpdateSubresource(m_encode_params, 0, nullptr, &encode_params, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(m_encode_params);
|
||||
|
||||
@ -109,7 +121,7 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will 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
|
||||
if (scale_by_half || g_renderer->GetEFBScale() != 1 || params.y_scale > 1.0f)
|
||||
if (scale_by_half || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f)
|
||||
D3D::SetLinearCopySampler();
|
||||
else
|
||||
D3D::SetPointCopySampler();
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
@ -38,8 +39,9 @@ public:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half);
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
|
||||
|
||||
private:
|
||||
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyParams& params);
|
||||
|
@ -627,8 +627,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
}
|
||||
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
||||
float Gamma)
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks)
|
||||
{
|
||||
ResetAPIState();
|
||||
|
||||
@ -650,7 +649,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
||||
auto* xfb_texture = static_cast<DXTexture*>(texture);
|
||||
|
||||
BlitScreen(xfb_region, targetRc, xfb_texture->GetRawTexIdentifier(),
|
||||
xfb_texture->GetConfig().width, xfb_texture->GetConfig().height, Gamma);
|
||||
xfb_texture->GetConfig().width, xfb_texture->GetConfig().height);
|
||||
|
||||
// Reset viewport for drawing text
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast<float>(m_backbuffer_width),
|
||||
@ -854,7 +853,7 @@ void Renderer::BBoxWrite(int index, u16 _value)
|
||||
}
|
||||
|
||||
void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
|
||||
u32 src_width, u32 src_height, float Gamma)
|
||||
u32 src_width, u32 src_height)
|
||||
{
|
||||
if (g_ActiveConfig.stereo_mode == StereoMode::SBS ||
|
||||
g_ActiveConfig.stereo_mode == StereoMode::TAB)
|
||||
@ -871,13 +870,13 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height,
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0);
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0f, 0);
|
||||
|
||||
D3D::context->RSSetViewports(1, &rightVp);
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height,
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1);
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0f, 1);
|
||||
}
|
||||
else if (g_ActiveConfig.stereo_mode == StereoMode::Nvidia3DVision)
|
||||
{
|
||||
@ -896,13 +895,13 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height,
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0);
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0f, 0);
|
||||
|
||||
D3D::context->RSSetViewports(1, &rightVp);
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height,
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1);
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0f, 1);
|
||||
|
||||
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
|
||||
// recognize the signature and automatically include the right eye frame.
|
||||
@ -927,7 +926,7 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D
|
||||
nullptr;
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, pixelShader,
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), geomShader, Gamma);
|
||||
VertexShaderCache::GetSimpleInputLayout(), geomShader, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
@ -84,7 +84,7 @@ private:
|
||||
void UpdateBackbufferSize();
|
||||
|
||||
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
|
||||
u32 src_width, u32 src_height, float Gamma);
|
||||
u32 src_width, u32 src_height);
|
||||
|
||||
void UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size);
|
||||
void UpdateUtilityVertexBuffer(const void* vertices, u32 vertex_stride, u32 num_vertices);
|
||||
|
@ -33,10 +33,12 @@ static std::unique_ptr<PSTextureEncoder> g_encoder;
|
||||
|
||||
void TextureCache::CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
g_encoder->Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, src_rect,
|
||||
scale_by_half);
|
||||
scale_by_half, y_scale, gamma, clamp_top, clamp_bottom, filter_coefficients);
|
||||
}
|
||||
|
||||
const char palette_shader[] =
|
||||
@ -137,9 +139,9 @@ void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
D3D::stateman->SetTexture(1, palette_buf_srv);
|
||||
|
||||
// TODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
|
||||
float params[4] = {source->format == TextureFormat::I4 ? 15.f : 255.f};
|
||||
D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, ¶ms, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(palette_uniform);
|
||||
float params[8] = {source->format == TextureFormat::I4 ? 15.f : 255.f};
|
||||
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, ¶ms, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(uniform_buffer);
|
||||
|
||||
const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, source->GetWidth(), source->GetHeight());
|
||||
|
||||
@ -180,7 +182,7 @@ TextureCache::TextureCache()
|
||||
|
||||
palette_buf = nullptr;
|
||||
palette_buf_srv = nullptr;
|
||||
palette_uniform = nullptr;
|
||||
uniform_buffer = nullptr;
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::IA8)] = GetConvertShader("IA8");
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB565)] = GetConvertShader("RGB565");
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB5A3)] = GetConvertShader("RGB5A3");
|
||||
@ -195,10 +197,10 @@ TextureCache::TextureCache()
|
||||
CHECK(SUCCEEDED(hr), "create palette decoder lut srv");
|
||||
D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv");
|
||||
const D3D11_BUFFER_DESC cbdesc =
|
||||
CD3D11_BUFFER_DESC(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
||||
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform);
|
||||
CD3D11_BUFFER_DESC(sizeof(float) * 8, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
||||
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &uniform_buffer);
|
||||
CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer");
|
||||
D3D::SetDebugObjectName(palette_uniform,
|
||||
D3D::SetDebugObjectName(uniform_buffer,
|
||||
"a constant buffer used in TextureCache::CopyRenderTargetToTexture");
|
||||
}
|
||||
|
||||
@ -209,7 +211,7 @@ TextureCache::~TextureCache()
|
||||
|
||||
SAFE_RELEASE(palette_buf);
|
||||
SAFE_RELEASE(palette_buf_srv);
|
||||
SAFE_RELEASE(palette_uniform);
|
||||
SAFE_RELEASE(uniform_buffer);
|
||||
for (auto*& shader : palette_pixel_shader)
|
||||
SAFE_RELEASE(shader);
|
||||
for (auto& iter : m_efb_to_tex_pixel_shaders)
|
||||
@ -218,7 +220,9 @@ TextureCache::~TextureCache()
|
||||
|
||||
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
const EFBRectangle& src_rect, bool scale_by_half,
|
||||
EFBCopyFormat dst_format, bool is_intensity)
|
||||
EFBCopyFormat dst_format, bool is_intensity, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
auto* destination_texture = static_cast<DXTexture*>(entry->texture.get());
|
||||
|
||||
@ -260,6 +264,27 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
else
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
struct PixelConstants
|
||||
{
|
||||
float filter_coefficients[3];
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
float pixel_height;
|
||||
u32 padding;
|
||||
};
|
||||
PixelConstants constants;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
constants.filter_coefficients[i] = filter_coefficients[i] / 64.0f;
|
||||
constants.gamma_rcp = 1.0f / gamma;
|
||||
constants.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
constants.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
|
||||
constants.pixel_height =
|
||||
g_ActiveConfig.bCopyEFBScaled ? 1.0f / g_renderer->GetTargetHeight() : 1.0f / EFB_HEIGHT;
|
||||
constants.padding = 0;
|
||||
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, &constants, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(uniform_buffer);
|
||||
|
||||
// Make sure we don't draw with the texture set as both a source and target.
|
||||
// (This can happen because we don't unbind textures when we free them.)
|
||||
D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV());
|
||||
|
@ -34,11 +34,13 @@ private:
|
||||
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override;
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format,
|
||||
bool is_intensity) override;
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
@ -46,7 +48,7 @@ private:
|
||||
|
||||
ID3D11Buffer* palette_buf;
|
||||
ID3D11ShaderResourceView* palette_buf_srv;
|
||||
ID3D11Buffer* palette_uniform;
|
||||
ID3D11Buffer* uniform_buffer;
|
||||
ID3D11PixelShader* palette_pixel_shader[3];
|
||||
|
||||
std::map<TextureConversionShaderGen::TCShaderUid, ID3D11PixelShader*> m_efb_to_tex_pixel_shaders;
|
||||
|
@ -92,7 +92,7 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Renderer::SwapImpl(AbstractTexture*, const EFBRectangle&, u64, float)
|
||||
void Renderer::SwapImpl(AbstractTexture*, const EFBRectangle&, u64)
|
||||
{
|
||||
UpdateActiveConfig();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
void BBoxWrite(int index, u16 value) override {}
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override
|
||||
|
@ -27,12 +27,15 @@ public:
|
||||
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
{
|
||||
}
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity) override
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -1365,8 +1365,7 @@ void Renderer::ApplyBlendingState(const BlendingState state, bool force)
|
||||
}
|
||||
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
||||
float Gamma)
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks)
|
||||
{
|
||||
if (g_ogl_config.bSupportsDebug)
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ public:
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
@ -68,10 +68,18 @@ constexpr const char* geometry_program = "layout(triangles) in;\n"
|
||||
|
||||
void TextureCache::CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
// Flip top/bottom due to lower-left coordinate system.
|
||||
float clamp_top_val =
|
||||
clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f;
|
||||
float clamp_bottom_val =
|
||||
clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 0.0f;
|
||||
TextureConverter::EncodeToRamFromTexture(dst, params, native_width, bytes_per_row, num_blocks_y,
|
||||
memory_stride, src_rect, scale_by_half);
|
||||
memory_stride, src_rect, scale_by_half, y_scale, gamma,
|
||||
clamp_top_val, clamp_bottom_val, filter_coefficients);
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
@ -483,7 +491,9 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u
|
||||
|
||||
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
const EFBRectangle& src_rect, bool scale_by_half,
|
||||
EFBCopyFormat dst_format, bool is_intensity)
|
||||
EFBCopyFormat dst_format, bool is_intensity, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
auto* destination_texture = static_cast<OGLTexture*>(entry->texture.get());
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
@ -528,6 +538,11 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
code.GetBuffer(), geo_program);
|
||||
|
||||
shader.position_uniform = glGetUniformLocation(shader.shader.glprogid, "copy_position");
|
||||
shader.pixel_height_uniform = glGetUniformLocation(shader.shader.glprogid, "pixel_height");
|
||||
shader.gamma_rcp_uniform = glGetUniformLocation(shader.shader.glprogid, "gamma_rcp");
|
||||
shader.clamp_tb_uniform = glGetUniformLocation(shader.shader.glprogid, "clamp_tb");
|
||||
shader.filter_coefficients_uniform =
|
||||
glGetUniformLocation(shader.shader.glprogid, "filter_coefficients");
|
||||
}
|
||||
|
||||
shader.shader.Bind();
|
||||
@ -535,6 +550,15 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
TargetRectangle R = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
glUniform4f(shader.position_uniform, static_cast<float>(R.left), static_cast<float>(R.top),
|
||||
static_cast<float>(R.right), static_cast<float>(R.bottom));
|
||||
glUniform1f(shader.pixel_height_uniform, g_ActiveConfig.bCopyEFBScaled ?
|
||||
1.0f / g_renderer->GetTargetHeight() :
|
||||
1.0f / EFB_HEIGHT);
|
||||
glUniform1f(shader.gamma_rcp_uniform, 1.0f / gamma);
|
||||
glUniform2f(shader.clamp_tb_uniform,
|
||||
clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f,
|
||||
clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 0.0f);
|
||||
glUniform3f(shader.filter_coefficients_uniform, filter_coefficients[0] / 64.0f,
|
||||
filter_coefficients[1] / 64.0f, filter_coefficients[2] / 64.0f);
|
||||
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
@ -65,11 +65,13 @@ private:
|
||||
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override;
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format,
|
||||
bool is_intensity) override;
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
bool CompileShaders() override;
|
||||
void DeleteShaders() override;
|
||||
@ -84,6 +86,10 @@ private:
|
||||
{
|
||||
SHADER shader;
|
||||
GLuint position_uniform;
|
||||
GLuint pixel_height_uniform;
|
||||
GLuint gamma_rcp_uniform;
|
||||
GLuint clamp_tb_uniform;
|
||||
GLuint filter_coefficients_uniform;
|
||||
};
|
||||
|
||||
std::map<TextureConversionShaderGen::TCShaderUid, EFBCopyShader> m_efb_copy_programs;
|
||||
|
@ -39,6 +39,9 @@ struct EncodingProgram
|
||||
SHADER program;
|
||||
GLint copy_position_uniform;
|
||||
GLint y_scale_uniform;
|
||||
GLint gamma_rcp_uniform;
|
||||
GLint clamp_tb_uniform;
|
||||
GLint filter_coefficients_uniform;
|
||||
};
|
||||
|
||||
std::map<EFBCopyParams, EncodingProgram> s_encoding_programs;
|
||||
@ -81,6 +84,10 @@ static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params)
|
||||
|
||||
program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position");
|
||||
program.y_scale_uniform = glGetUniformLocation(program.program.glprogid, "y_scale");
|
||||
program.gamma_rcp_uniform = glGetUniformLocation(program.program.glprogid, "gamma_rcp");
|
||||
program.clamp_tb_uniform = glGetUniformLocation(program.program.glprogid, "clamp_tb");
|
||||
program.filter_coefficients_uniform =
|
||||
glGetUniformLocation(program.program.glprogid, "filter_coefficients");
|
||||
return s_encoding_programs.emplace(params, program).first->second;
|
||||
}
|
||||
|
||||
@ -137,7 +144,9 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line
|
||||
|
||||
void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, float clamp_top, float clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
@ -146,14 +155,18 @@ void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 nativ
|
||||
texconv_shader.program.Bind();
|
||||
glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width,
|
||||
scale_by_half ? 2 : 1);
|
||||
glUniform1f(texconv_shader.y_scale_uniform, params.y_scale);
|
||||
glUniform1f(texconv_shader.y_scale_uniform, y_scale);
|
||||
glUniform1f(texconv_shader.gamma_rcp_uniform, 1.0f / gamma);
|
||||
glUniform2f(texconv_shader.clamp_tb_uniform, clamp_top, clamp_bottom);
|
||||
glUniform3i(texconv_shader.filter_coefficients_uniform, filter_coefficients[0],
|
||||
filter_coefficients[1], filter_coefficients[2]);
|
||||
|
||||
const GLuint read_texture = params.depth ?
|
||||
FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
|
||||
FramebufferManager::ResolveAndGetRenderTarget(src_rect);
|
||||
|
||||
EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride,
|
||||
scale_by_half && !params.depth, params.y_scale);
|
||||
scale_by_half && !params.depth, y_scale);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
@ -7,10 +7,9 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
struct EFBCopyParams;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
// Converts textures between formats using shaders
|
||||
@ -21,9 +20,11 @@ void Init();
|
||||
void Shutdown();
|
||||
|
||||
// returns size of the encoded data (in bytes)
|
||||
void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half);
|
||||
void EncodeToRamFromTexture(
|
||||
u8* dest_ptr, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma, float clamp_top, float clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
@ -502,6 +502,23 @@ static u32 VerticalFilter(const std::array<u32, 3>& colors,
|
||||
return out_color32;
|
||||
}
|
||||
|
||||
static u32 GammaCorrection(u32 color, const float gamma_rcp)
|
||||
{
|
||||
u8 in_colors[4];
|
||||
std::memcpy(&in_colors, &color, sizeof(in_colors));
|
||||
|
||||
u8 out_color[4];
|
||||
for (int i = BLU_C; i <= RED_C; i++)
|
||||
{
|
||||
out_color[i] = static_cast<u8>(
|
||||
MathUtil::Clamp(std::pow(in_colors[i] / 255.0f, gamma_rcp) * 255.0f, 0.0f, 255.0f));
|
||||
}
|
||||
|
||||
u32 out_color32;
|
||||
std::memcpy(&out_color32, out_color, sizeof(out_color32));
|
||||
return out_color32;
|
||||
}
|
||||
|
||||
// For internal used only, return a non-normalized value, which saves work later.
|
||||
static yuv444 ConvertColorToYUV(u32 color)
|
||||
{
|
||||
@ -530,8 +547,7 @@ u8* GetPixelPointer(u16 x, u16 y, bool depth)
|
||||
}
|
||||
|
||||
void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rect, float y_scale,
|
||||
bool clamp_top, bool clamp_bottom, float Gamma,
|
||||
const std::array<u8, 7>& filterCoefficients)
|
||||
float gamma)
|
||||
{
|
||||
if (!xfb_in_ram)
|
||||
{
|
||||
@ -539,8 +555,12 @@ void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rec
|
||||
return;
|
||||
}
|
||||
|
||||
int left = source_rect.left;
|
||||
int right = source_rect.right;
|
||||
const int left = source_rect.left;
|
||||
const int right = source_rect.right;
|
||||
const bool clamp_top = bpmem.triggerEFBCopy.clamp_top;
|
||||
const bool clamp_bottom = bpmem.triggerEFBCopy.clamp_bottom;
|
||||
const float gamma_rcp = 1.0f / gamma;
|
||||
const auto filter_coefficients = bpmem.copyfilter.GetCoefficients();
|
||||
|
||||
// this assumes copies will always start on an even (YU) pixel and the
|
||||
// copy always has an even width, which might not be true.
|
||||
@ -575,9 +595,10 @@ void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rec
|
||||
std::array<u32, 3> colors = {{GetColor(x, y_prev), GetColor(x, y), GetColor(x, y_next)}};
|
||||
|
||||
// Vertical Filter (Multisampling resolve, deflicker, brightness)
|
||||
u32 filtered = VerticalFilter(colors, filterCoefficients);
|
||||
u32 filtered = VerticalFilter(colors, filter_coefficients);
|
||||
|
||||
// TODO: Gamma correction happens here.
|
||||
// Gamma correction happens here.
|
||||
filtered = GammaCorrection(filtered, gamma_rcp);
|
||||
|
||||
scanline[i] = ConvertColorToYUV(filtered);
|
||||
}
|
||||
|
@ -59,8 +59,7 @@ u32 GetDepth(u16 x, u16 y);
|
||||
u8* GetPixelPointer(u16 x, u16 y, bool depth);
|
||||
|
||||
void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rect, float y_scale,
|
||||
bool clamp_top, bool clamp_bottom, float Gamma,
|
||||
const std::array<u8, 7>& filterCoefficients);
|
||||
float gamma);
|
||||
|
||||
extern u32 perf_values[PQ_NUM_MEMBERS];
|
||||
inline void IncPerfCounterQuadCount(PerfQueryType type)
|
||||
|
@ -87,8 +87,7 @@ std::unique_ptr<AbstractPipeline> SWRenderer::CreatePipeline(const AbstractPipel
|
||||
}
|
||||
|
||||
// Called on the GPU thread
|
||||
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
||||
float Gamma)
|
||||
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks)
|
||||
{
|
||||
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
|
||||
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
@ -18,15 +18,18 @@ public:
|
||||
}
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
{
|
||||
TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride,
|
||||
src_rect, scale_by_half);
|
||||
src_rect, scale_by_half, y_scale, gamma);
|
||||
}
|
||||
|
||||
private:
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity) override
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
{
|
||||
// TODO: If we ever want to "fake" vram textures, we would need to implement this
|
||||
}
|
||||
|
@ -1469,15 +1469,12 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b
|
||||
}
|
||||
|
||||
void Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half)
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma)
|
||||
{
|
||||
if (params.copy_format == EFBCopyFormat::XFB)
|
||||
{
|
||||
static constexpr std::array<float, 4> gamma_LUT = {1.0f, 1.7f, 2.2f, 1.0f};
|
||||
EfbInterface::EncodeXFB(dst, native_width, src_rect, params.y_scale,
|
||||
!!bpmem.triggerEFBCopy.clamp_top, !!bpmem.triggerEFBCopy.clamp_bottom,
|
||||
gamma_LUT[bpmem.triggerEFBCopy.gamma],
|
||||
bpmem.copyfilter.GetCoefficients());
|
||||
EfbInterface::EncodeXFB(dst, native_width, src_rect, y_scale, gamma);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,12 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
struct EFBCopyParams;
|
||||
|
||||
namespace TextureEncoder
|
||||
{
|
||||
void Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half);
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma);
|
||||
}
|
||||
|
@ -697,8 +697,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
BindEFBToStateTracker();
|
||||
}
|
||||
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
||||
float Gamma)
|
||||
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks)
|
||||
{
|
||||
// Pending/batched EFB pokes should be included in the final image.
|
||||
FramebufferManager::GetInstance()->FlushEFBPokes();
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable,
|
||||
u32 color, u32 z) override;
|
||||
|
@ -100,7 +100,9 @@ void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
|
||||
void TextureCache::CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
// Flush EFB pokes first, as they're expected to be included.
|
||||
FramebufferManager::GetInstance()->FlushEFBPokes();
|
||||
@ -131,9 +133,9 @@ void TextureCache::CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_widt
|
||||
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
m_texture_converter->EncodeTextureToMemory(src_texture->GetView(), dst, params, native_width,
|
||||
bytes_per_row, num_blocks_y, memory_stride, src_rect,
|
||||
scale_by_half);
|
||||
m_texture_converter->EncodeTextureToMemory(
|
||||
src_texture->GetView(), dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride,
|
||||
src_rect, scale_by_half, y_scale, gamma, clamp_top, clamp_bottom, filter_coefficients);
|
||||
|
||||
// Transition back to original state
|
||||
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout);
|
||||
@ -209,7 +211,9 @@ void TextureCache::DeleteShaders()
|
||||
|
||||
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
const EFBRectangle& src_rect, bool scale_by_half,
|
||||
EFBCopyFormat dst_format, bool is_intensity)
|
||||
EFBCopyFormat dst_format, bool is_intensity, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
VKTexture* texture = static_cast<VKTexture*>(entry->texture.get());
|
||||
|
||||
@ -228,6 +232,26 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
// Fill uniform buffer.
|
||||
struct PixelUniforms
|
||||
{
|
||||
float filter_coefficients[3];
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
float pixel_height;
|
||||
u32 padding;
|
||||
};
|
||||
PixelUniforms uniforms;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
uniforms.filter_coefficients[i] = filter_coefficients[i] / 64.0f;
|
||||
uniforms.gamma_rcp = 1.0f / gamma;
|
||||
uniforms.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
uniforms.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
|
||||
uniforms.pixel_height =
|
||||
g_ActiveConfig.bCopyEFBScaled ? 1.0f / g_renderer->GetTargetHeight() : 1.0f / EFB_HEIGHT;
|
||||
uniforms.padding = 0;
|
||||
|
||||
// Transition EFB to shader resource before binding.
|
||||
// An out-of-bounds source region is valid here, and fine for the draw (since it is converted
|
||||
// to texture coordinates), but it's not valid to resolve an out-of-range rectangle.
|
||||
@ -274,6 +298,10 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
g_shader_cache->GetPassthroughVertexShader(),
|
||||
g_shader_cache->GetPassthroughGeometryShader(), shader);
|
||||
|
||||
u8* ubo_ptr = draw.AllocatePSUniforms(sizeof(PixelUniforms));
|
||||
std::memcpy(ubo_ptr, &uniforms, sizeof(PixelUniforms));
|
||||
draw.CommitPSUniforms(sizeof(PixelUniforms));
|
||||
|
||||
draw.SetPSSampler(0, src_texture->GetView(), src_sampler);
|
||||
|
||||
VkRect2D dest_region = {{0, 0}, {texture->GetConfig().width, texture->GetConfig().height}};
|
||||
|
@ -38,7 +38,8 @@ public:
|
||||
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override;
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
bool SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format) override;
|
||||
|
||||
@ -52,8 +53,9 @@ public:
|
||||
|
||||
private:
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format,
|
||||
bool is_intensity) override;
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
std::unique_ptr<StreamBuffer> m_texture_upload_buffer;
|
||||
|
||||
|
@ -38,6 +38,11 @@ struct EFBEncodeParams
|
||||
{
|
||||
std::array<s32, 4> position_uniform;
|
||||
float y_scale;
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
s32 filter_coefficients[3];
|
||||
u32 padding;
|
||||
};
|
||||
}
|
||||
TextureConverter::TextureConverter()
|
||||
@ -201,10 +206,11 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
|
||||
draw.EndRenderPass();
|
||||
}
|
||||
|
||||
void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr,
|
||||
const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half)
|
||||
void TextureConverter::EncodeTextureToMemory(
|
||||
VkImageView src_texture, u8* dest_ptr, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
VkShaderModule shader = GetEncodingShader(params);
|
||||
if (shader == VK_NULL_HANDLE)
|
||||
@ -236,14 +242,21 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
|
||||
encoder_params.position_uniform[1] = src_rect.top;
|
||||
encoder_params.position_uniform[2] = static_cast<s32>(native_width);
|
||||
encoder_params.position_uniform[3] = scale_by_half ? 2 : 1;
|
||||
encoder_params.y_scale = params.y_scale;
|
||||
draw.SetPushConstants(&encoder_params, sizeof(encoder_params));
|
||||
encoder_params.y_scale = y_scale;
|
||||
encoder_params.gamma_rcp = 1.0f / gamma;
|
||||
encoder_params.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
encoder_params.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 0.0f;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
encoder_params.filter_coefficients[i] = filter_coefficients[i];
|
||||
u8* ubo_ptr = draw.AllocatePSUniforms(sizeof(EFBEncodeParams));
|
||||
std::memcpy(ubo_ptr, &encoder_params, sizeof(EFBEncodeParams));
|
||||
draw.CommitPSUniforms(sizeof(EFBEncodeParams));
|
||||
|
||||
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
||||
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
|
||||
// complex down filtering to average all pixels and produce the correct result.
|
||||
bool linear_filter =
|
||||
(scale_by_half && !params.depth) || g_renderer->GetEFBScale() != 1 || params.y_scale > 1.0f;
|
||||
(scale_by_half && !params.depth) || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f;
|
||||
draw.SetPSSampler(0, src_texture,
|
||||
linear_filter ? g_object_cache->GetLinearSampler() :
|
||||
g_object_cache->GetPointSampler());
|
||||
|
@ -40,9 +40,12 @@ public:
|
||||
|
||||
// Uses an encoding shader to copy src_texture to dest_ptr.
|
||||
// NOTE: Executes the current command buffer.
|
||||
void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, const EFBCopyParams& params,
|
||||
u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
|
||||
u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half);
|
||||
void
|
||||
EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, const EFBCopyParams& params,
|
||||
u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
|
||||
|
||||
bool SupportsTextureDecoding(TextureFormat format, TLUTFormat palette_format);
|
||||
void DecodeTexture(VkCommandBuffer command_buffer, TextureCache::TCacheEntry* entry,
|
||||
|
Reference in New Issue
Block a user