summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/TextureConversionShader.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@users.noreply.github.com>2018-05-01 19:31:54 +1000
committerGitHub <noreply@github.com>2018-05-01 19:31:54 +1000
commitc46882142bffbfc18103d4c977dd2551408e229c (patch)
tree5c27fdafb147e9cdea441dc192049c243f415496 /Source/Core/VideoCommon/TextureConversionShader.cpp
parent42d73deaed9e79e8d2e45c1a0ebfa69d19a9c9b3 (diff)
parentea4090d92c51a53ee7aedcd1fe7871861a78550c (diff)
Merge pull request #6369 from stenzek/xfb-copy-filter
Implement copy filter (deflickering/brightness) and XFB gamma
Diffstat (limited to 'Source/Core/VideoCommon/TextureConversionShader.cpp')
-rw-r--r--Source/Core/VideoCommon/TextureConversionShader.cpp245
1 files changed, 150 insertions, 95 deletions
diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp
index 4d1539572c..1912f2aee5 100644
--- a/Source/Core/VideoCommon/TextureConversionShader.cpp
+++ b/Source/Core/VideoCommon/TextureConversionShader.cpp
@@ -57,19 +57,44 @@ u16 GetEncodedSampleCount(EFBCopyFormat format)
}
}
-// block dimensions : widthStride, heightStride
-// texture dims : width, height, x offset, y offset
-static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType)
+static void WriteHeader(char*& p, APIType ApiType)
{
- // left, top, of source rectangle within source texture
- // width of the destination rectangle, scale_factor (1 or 2)
- if (ApiType == APIType::Vulkan)
- WRITE(p,
- "layout(std140, push_constant) uniform PCBlock { int4 position; float y_scale; } PC;\n");
- else
+ if (ApiType == APIType::OpenGL)
{
+ // left, top, of source rectangle within source texture
+ // width of the destination rectangle, scale_factor (1 or 2)
WRITE(p, "uniform int4 position;\n");
WRITE(p, "uniform float y_scale;\n");
+ WRITE(p, "uniform float gamma_rcp;\n");
+ WRITE(p, "uniform float2 clamp_tb;\n");
+ WRITE(p, "uniform int3 filter_coefficients;\n");
+ WRITE(p, "#define samp0 samp9\n");
+ WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n");
+ WRITE(p, "FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n");
+ }
+ else if (ApiType == APIType::Vulkan)
+ {
+ WRITE(p, "UBO_BINDING(std140, 1) uniform PSBlock {\n");
+ WRITE(p, " int4 position;\n");
+ WRITE(p, " float y_scale;\n");
+ WRITE(p, " float gamma_rcp;\n");
+ WRITE(p, " float2 clamp_tb;\n");
+ WRITE(p, " int3 filter_coefficients;\n");
+ WRITE(p, "};\n");
+ WRITE(p, "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
+ WRITE(p, "FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n");
+ }
+ else // D3D
+ {
+ WRITE(p, "cbuffer PSBlock : register(b0) {\n");
+ WRITE(p, " int4 position;\n");
+ WRITE(p, " float y_scale;\n");
+ WRITE(p, " float gamma_rcp;\n");
+ WRITE(p, " float2 clamp_tb;\n");
+ WRITE(p, " int3 filter_coefficients;\n");
+ WRITE(p, "};\n");
+ WRITE(p, "sampler samp0 : register(s0);\n");
+ WRITE(p, "Texture2DArray Tex0 : register(t0);\n");
}
// D3D does not have roundEven(), only round(), which is specified "to the nearest integer".
@@ -96,39 +121,100 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType)
WRITE(p, " val = int4(val.r >> 3, val.g >> 2, val.b >> 3, 1);\n");
WRITE(p, " return float4(val) / float4(31.0, 63.0, 31.0, 1.0);\n");
WRITE(p, "}\n");
+}
- int blkW = TexDecoder_GetEFBCopyBlockWidthInTexels(format);
- int blkH = TexDecoder_GetEFBCopyBlockHeightInTexels(format);
- int samples = GetEncodedSampleCount(format);
+static void WriteSampleFunction(char*& p, const EFBCopyParams& params, APIType ApiType)
+{
+ auto WriteSampleOp = [&](int yoffset) {
+ if (!params.depth)
+ {
+ switch (params.efb_format)
+ {
+ case PEControl::RGB8_Z24:
+ WRITE(p, "RGBA8ToRGB8(");
+ break;
+ case PEControl::RGBA6_Z24:
+ WRITE(p, "RGBA8ToRGBA6(");
+ break;
+ case PEControl::RGB565_Z16:
+ WRITE(p, "RGBA8ToRGB565(");
+ break;
+ default:
+ WRITE(p, "(");
+ break;
+ }
+ }
+ else
+ {
+ // Handle D3D depth inversion.
+ if (ApiType == APIType::D3D || ApiType == APIType::Vulkan)
+ WRITE(p, "1.0 - (");
+ else
+ WRITE(p, "(");
+ }
- if (ApiType == APIType::OpenGL)
- {
- WRITE(p, "#define samp0 samp9\n");
- WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n");
+ if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
+ WRITE(p, "texture(samp0, float3(");
+ else
+ WRITE(p, "Tex0.Sample(samp0, float3(");
- WRITE(p, "FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n");
- WRITE(p, "void main()\n");
- WRITE(p, "{\n"
- " int2 sampleUv;\n"
- " int2 uv1 = int2(gl_FragCoord.xy);\n");
- }
- else if (ApiType == APIType::Vulkan)
- {
- WRITE(p, "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
- WRITE(p, "FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n");
+ WRITE(p, "uv.x + xoffset * pixel_size.x, ");
+
+ // Reverse the direction for OpenGL, since positive numbers are distance from the bottom row.
+ if (yoffset != 0)
+ {
+ if (ApiType == APIType::OpenGL)
+ WRITE(p, "clamp(uv.y - float(%d) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
+ else
+ WRITE(p, "clamp(uv.y + float(%d) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
+ }
+ else
+ {
+ WRITE(p, "uv.y");
+ }
+
+ WRITE(p, ", 0.0)))");
+ };
+ // The copy filter applies to both color and depth copies. This has been verified on hardware.
+ // The filter is only applied to the RGB channels, the alpha channel is left intact.
+ WRITE(p, "float4 SampleEFB(float2 uv, float2 pixel_size, int xoffset)\n");
+ WRITE(p, "{\n");
+ WRITE(p, " float4 prev_row = ");
+ WriteSampleOp(-1);
+ WRITE(p, ";\n");
+ WRITE(p, " float4 current_row = ");
+ WriteSampleOp(0);
+ WRITE(p, ";\n");
+ WRITE(p, " float4 next_row = ");
+ WriteSampleOp(1);
+ WRITE(p, ";\n");
+ WRITE(p,
+ " float3 col = float3(clamp((int3(prev_row.rgb * 255.0) * filter_coefficients[0] +\n"
+ " int3(current_row.rgb * 255.0) * filter_coefficients[1] +\n"
+ " int3(next_row.rgb * 255.0) * filter_coefficients[2]) >> 6,\n"
+ " int3(0, 0, 0), int3(255, 255, 255))) / 255.0;\n");
+ WRITE(p, " return float4(col, current_row.a);\n");
+ WRITE(p, "}\n");
+}
+
+// block dimensions : widthStride, heightStride
+// texture dims : width, height, x offset, y offset
+static void WriteSwizzler(char*& p, const EFBCopyParams& params, EFBCopyFormat format,
+ APIType ApiType)
+{
+ WriteHeader(p, ApiType);
+ WriteSampleFunction(p, params, ApiType);
+
+ if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
+ {
WRITE(p, "void main()\n");
WRITE(p, "{\n"
" int2 sampleUv;\n"
- " int2 uv1 = int2(gl_FragCoord.xy);\n"
- " int4 position = PC.position;\n"
- " float y_scale = PC.y_scale;\n");
+ " int2 uv1 = int2(gl_FragCoord.xy);\n");
}
else // D3D
{
- WRITE(p, "sampler samp0 : register(s0);\n");
- WRITE(p, "Texture2DArray Tex0 : register(t0);\n");
-
WRITE(p, "void main(\n");
WRITE(p, " out float4 ocol0 : SV_Target, in float4 rawpos : SV_Position)\n");
WRITE(p, "{\n"
@@ -136,6 +222,10 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType)
" int2 uv1 = int2(rawpos.xy);\n");
}
+ int blkW = TexDecoder_GetEFBCopyBlockWidthInTexels(format);
+ int blkH = TexDecoder_GetEFBCopyBlockHeightInTexels(format);
+ int samples = GetEncodedSampleCount(format);
+
WRITE(p, " int x_block_position = (uv1.x >> %d) << %d;\n", IntLog2(blkH * blkW / samples),
IntLog2(blkW));
WRITE(p, " int y_block_position = uv1.y << %d;\n", IntLog2(blkH));
@@ -167,51 +257,13 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType)
WRITE(p, " uv0.y = 1.0-uv0.y;\n");
}
- WRITE(p, " float sample_offset = float(position.w) / float(%d);\n", EFB_WIDTH);
+ WRITE(p, " float2 pixel_size = position.ww / float2(%d, %d);\n", EFB_WIDTH, EFB_HEIGHT);
}
static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset,
APIType ApiType, const EFBCopyParams& params)
{
- WRITE(p, " %s = ", dest);
-
- if (!params.depth)
- {
- switch (params.efb_format)
- {
- case PEControl::RGB8_Z24:
- WRITE(p, "RGBA8ToRGB8(");
- break;
- case PEControl::RGBA6_Z24:
- WRITE(p, "RGBA8ToRGBA6(");
- break;
- case PEControl::RGB565_Z16:
- WRITE(p, "RGBA8ToRGB565(");
- break;
- default:
- WRITE(p, "(");
- break;
- }
- }
- else
- {
- // Handle D3D depth inversion.
- if (ApiType == APIType::D3D || ApiType == APIType::Vulkan)
- WRITE(p, "1.0 - (");
- else
- WRITE(p, "(");
- }
-
- if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
- {
- WRITE(p, "texture(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0))).%s;\n", xoffset,
- colorComp);
- }
- else
- {
- WRITE(p, "Tex0.Sample(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0))).%s;\n", xoffset,
- colorComp);
- }
+ WRITE(p, " %s = SampleEFB(uv0, pixel_size, %d).%s;\n", dest, xoffset, colorComp);
}
static void WriteColorToIntensity(char*& p, const char* src, const char* dest)
@@ -239,7 +291,7 @@ static void WriteEncoderEnd(char*& p)
static void WriteI8Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::R8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::R8, ApiType);
WRITE(p, " float3 texSample;\n");
WriteSampleColor(p, "rgb", "texSample", 0, ApiType, params);
@@ -261,7 +313,7 @@ static void WriteI8Encoder(char*& p, APIType ApiType, const EFBCopyParams& param
static void WriteI4Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::R4, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::R4, ApiType);
WRITE(p, " float3 texSample;\n");
WRITE(p, " float4 color0;\n");
WRITE(p, " float4 color1;\n");
@@ -302,7 +354,7 @@ static void WriteI4Encoder(char*& p, APIType ApiType, const EFBCopyParams& param
static void WriteIA8Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RA8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RA8, ApiType);
WRITE(p, " float4 texSample;\n");
WriteSampleColor(p, "rgba", "texSample", 0, ApiType, params);
@@ -320,7 +372,7 @@ static void WriteIA8Encoder(char*& p, APIType ApiType, const EFBCopyParams& para
static void WriteIA4Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RA4, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RA4, ApiType);
WRITE(p, " float4 texSample;\n");
WRITE(p, " float4 color0;\n");
WRITE(p, " float4 color1;\n");
@@ -352,7 +404,7 @@ static void WriteIA4Encoder(char*& p, APIType ApiType, const EFBCopyParams& para
static void WriteRGB565Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RGB565, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RGB565, ApiType);
WRITE(p, " float3 texSample0;\n");
WRITE(p, " float3 texSample1;\n");
@@ -377,7 +429,7 @@ static void WriteRGB565Encoder(char*& p, APIType ApiType, const EFBCopyParams& p
static void WriteRGB5A3Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RGB5A3, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RGB5A3, ApiType);
WRITE(p, " float4 texSample;\n");
WRITE(p, " float color0;\n");
@@ -441,7 +493,7 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType, const EFBCopyParams& p
static void WriteRGBA8Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RGBA8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RGBA8, ApiType);
WRITE(p, " float4 texSample;\n");
WRITE(p, " float4 color0;\n");
@@ -466,7 +518,7 @@ static void WriteRGBA8Encoder(char*& p, APIType ApiType, const EFBCopyParams& pa
static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::R4, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::R4, ApiType);
WRITE(p, " float4 color0;\n");
WRITE(p, " float4 color1;\n");
@@ -488,7 +540,7 @@ static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, const EF
static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::R8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::R8, ApiType);
WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, params);
WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, params);
@@ -501,7 +553,7 @@ static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, const EF
static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType,
const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RA4, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RA4, ApiType);
WRITE(p, " float2 texSample;\n");
WRITE(p, " float4 color0;\n");
WRITE(p, " float4 color1;\n");
@@ -532,7 +584,7 @@ static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType,
static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType,
const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RA8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RA8, ApiType);
WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType, params);
WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType, params);
@@ -543,7 +595,7 @@ static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType,
static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType,
const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::G8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::G8, ApiType);
WRITE(p, " float depth;\n");
@@ -564,7 +616,7 @@ static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType,
static void WriteZ16Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RA8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RA8, ApiType);
WRITE(p, " float depth;\n");
WRITE(p, " float3 expanded;\n");
@@ -596,7 +648,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType, const EFBCopyParams& para
static void WriteZ16LEncoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::GB8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::GB8, ApiType);
WRITE(p, " float depth;\n");
WRITE(p, " float3 expanded;\n");
@@ -632,7 +684,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType, const EFBCopyParams& par
static void WriteZ24Encoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::RGBA8, ApiType);
+ WriteSwizzler(p, params, EFBCopyFormat::RGBA8, ApiType);
WRITE(p, " float depth0;\n");
WRITE(p, " float depth1;\n");
@@ -672,18 +724,21 @@ static void WriteZ24Encoder(char*& p, APIType ApiType, const EFBCopyParams& para
static void WriteXFBEncoder(char*& p, APIType ApiType, const EFBCopyParams& params)
{
- WriteSwizzler(p, EFBCopyFormat::XFB, ApiType);
-
- WRITE(p, " float3 y_const = float3(0.257, 0.504, 0.098);\n");
- WRITE(p, " float3 u_const = float3(-0.148, -0.291, 0.439);\n");
- WRITE(p, " float3 v_const = float3(0.439, -0.368, -0.071);\n");
- WRITE(p, " float3 color0;\n");
- WRITE(p, " float3 color1;\n");
+ WriteSwizzler(p, params, EFBCopyFormat::XFB, ApiType);
+ WRITE(p, "float3 color0, color1;\n");
WriteSampleColor(p, "rgb", "color0", 0, ApiType, params);
WriteSampleColor(p, "rgb", "color1", 1, ApiType, params);
- WRITE(p, " float3 average = (color0 + color1) * 0.5;\n");
+ // Gamma is only applied to XFB copies.
+ WRITE(p, " color0 = pow(color0, gamma_rcp.xxx);\n");
+ WRITE(p, " color1 = pow(color1, gamma_rcp.xxx);\n");
+
+ // Convert to YUV.
+ WRITE(p, " const float3 y_const = float3(0.257, 0.504, 0.098);\n");
+ WRITE(p, " const float3 u_const = float3(-0.148, -0.291, 0.439);\n");
+ WRITE(p, " const float3 v_const = float3(0.439, -0.368, -0.071);\n");
+ WRITE(p, " float3 average = (color0 + color1) * 0.5;\n");
WRITE(p, " ocol0.b = dot(color0, y_const) + 0.0625;\n");
WRITE(p, " ocol0.g = dot(average, u_const) + 0.5;\n");
WRITE(p, " ocol0.r = dot(color1, y_const) + 0.0625;\n");