Permalink
Browse files

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.
  • Loading branch information...
stenzek committed Apr 29, 2018
1 parent a192a3b commit 9e798eec94a8ebe94c1ef8270b504b5698b2a0f5
Showing with 526 additions and 236 deletions.
  1. +2 −0 Source/Core/Core/Config/GraphicsSettings.cpp
  2. +1 −0 Source/Core/Core/Config/GraphicsSettings.h
  3. +1 −0 Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
  4. +18 −6 Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp
  5. +4 −2 Source/Core/VideoBackends/D3D/PSTextureEncoder.h
  6. +8 −9 Source/Core/VideoBackends/D3D/Render.cpp
  7. +2 −2 Source/Core/VideoBackends/D3D/Render.h
  8. +36 −11 Source/Core/VideoBackends/D3D/TextureCache.cpp
  9. +6 −4 Source/Core/VideoBackends/D3D/TextureCache.h
  10. +1 −1 Source/Core/VideoBackends/Null/Render.cpp
  11. +1 −1 Source/Core/VideoBackends/Null/Render.h
  12. +5 −2 Source/Core/VideoBackends/Null/TextureCache.h
  13. +1 −2 Source/Core/VideoBackends/OGL/Render.cpp
  14. +1 −1 Source/Core/VideoBackends/OGL/Render.h
  15. +27 −3 Source/Core/VideoBackends/OGL/TextureCache.cpp
  16. +9 −3 Source/Core/VideoBackends/OGL/TextureCache.h
  17. +16 −3 Source/Core/VideoBackends/OGL/TextureConverter.cpp
  18. +6 −5 Source/Core/VideoBackends/OGL/TextureConverter.h
  19. +27 −6 Source/Core/VideoBackends/Software/EfbInterface.cpp
  20. +1 −2 Source/Core/VideoBackends/Software/EfbInterface.h
  21. +1 −2 Source/Core/VideoBackends/Software/SWRenderer.cpp
  22. +1 −1 Source/Core/VideoBackends/Software/SWRenderer.h
  23. +6 −3 Source/Core/VideoBackends/Software/TextureCache.h
  24. +3 −6 Source/Core/VideoBackends/Software/TextureEncoder.cpp
  25. +3 −3 Source/Core/VideoBackends/Software/TextureEncoder.h
  26. +1 −2 Source/Core/VideoBackends/Vulkan/Renderer.cpp
  27. +1 −1 Source/Core/VideoBackends/Vulkan/Renderer.h
  28. +33 −5 Source/Core/VideoBackends/Vulkan/TextureCache.cpp
  29. +5 −3 Source/Core/VideoBackends/Vulkan/TextureCache.h
  30. +20 −7 Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
  31. +6 −3 Source/Core/VideoBackends/Vulkan/TextureConverter.h
  32. +3 −1 Source/Core/VideoCommon/BPMemory.h
  33. +8 −4 Source/Core/VideoCommon/BPStructs.cpp
  34. +1 −1 Source/Core/VideoCommon/RenderBase.cpp
  35. +1 −2 Source/Core/VideoCommon/RenderBase.h
  36. +40 −9 Source/Core/VideoCommon/TextureCacheBase.cpp
  37. +21 −10 Source/Core/VideoCommon/TextureCacheBase.h
  38. +150 −95 Source/Core/VideoCommon/TextureConversionShader.cpp
  39. +47 −15 Source/Core/VideoCommon/TextureConverterShaderGen.cpp
  40. +1 −0 Source/Core/VideoCommon/VideoConfig.cpp
  41. +1 −0 Source/Core/VideoCommon/VideoConfig.h
@@ -106,6 +106,8 @@ const ConfigInfo<std::string> GFX_ENHANCE_POST_SHADER{
{System::GFX, "Enhancements", "PostProcessingShader"}, ""};
const ConfigInfo<bool> GFX_ENHANCE_FORCE_TRUE_COLOR{{System::GFX, "Enhancements", "ForceTrueColor"},
true};
const ConfigInfo<bool> GFX_ENHANCE_DISABLE_COPY_FILTER{
{System::GFX, "Enhancements", "DisableCopyFilter"}, true};
// Graphics.Stereoscopy
@@ -80,6 +80,7 @@ extern const ConfigInfo<bool> GFX_ENHANCE_FORCE_FILTERING;
extern const ConfigInfo<int> GFX_ENHANCE_MAX_ANISOTROPY; // NOTE - this is x in (1 << x)
extern const ConfigInfo<std::string> GFX_ENHANCE_POST_SHADER;
extern const ConfigInfo<bool> GFX_ENHANCE_FORCE_TRUE_COLOR;
extern const ConfigInfo<bool> GFX_ENHANCE_DISABLE_COPY_FILTER;
// Graphics.Stereoscopy
@@ -85,6 +85,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
Config::GFX_ENHANCE_MAX_ANISOTROPY.location,
Config::GFX_ENHANCE_POST_SHADER.location,
Config::GFX_ENHANCE_FORCE_TRUE_COLOR.location,
Config::GFX_ENHANCE_DISABLE_COPY_FILTER.location,
// Graphics.Stereoscopy
@@ -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,15 +107,21 @@ 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);
// 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.
// 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 @@ class PSTextureEncoder final
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 @@ class Renderer : public ::Renderer
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 @@ class Renderer : public ::Renderer
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, &params, 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, &params, 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,19 +34,21 @@ class TextureCache : public TextureCacheBase
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 {}
ID3D11PixelShader* GetEFBToTexPixelShader(const TextureConversionShaderGen::TCShaderUid& uid);
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 @@ class Renderer : public ::Renderer
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 @@ class TextureCache : public TextureCacheBase
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 @@ class Renderer : public ::Renderer
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;
Oops, something went wrong.

0 comments on commit 9e798ee

Please sign in to comment.