VideoCommon/TextureConversionShader: Make use of fmt where applicable

Now that we've converted the shader generation over to ShaderCode, we
can now make use of the fmt-capable WriteFmt function.
This commit is contained in:
Lioncash 2020-01-23 14:11:28 -05:00
parent aa77dff3a2
commit 687f1f0330

View File

@ -6,6 +6,7 @@
#include <map>
#include <sstream>
#include <string_view>
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
@ -59,63 +60,63 @@ static void WriteHeader(ShaderCode& code, APIType api_type)
{
// left, top, of source rectangle within source texture
// width of the destination rectangle, scale_factor (1 or 2)
code.Write("UBO_BINDING(std140, 1) uniform PSBlock {\n"
" int4 position;\n"
" float y_scale;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float3 filter_coefficients;\n"
"};\n");
code.WriteFmt("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
" int4 position;\n"
" float y_scale;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float3 filter_coefficients;\n"
"}};\n");
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
code.Write("VARYING_LOCATION(0) in VertexData {\n"
" float3 v_tex0;\n"
"};\n");
code.WriteFmt("VARYING_LOCATION(0) in VertexData {{\n"
" float3 v_tex0;\n"
"}};\n");
}
else
{
code.Write("VARYING_LOCATION(0) in float3 v_tex0;\n");
code.WriteFmt("VARYING_LOCATION(0) in float3 v_tex0;\n");
}
code.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"
"FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n");
code.WriteFmt("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"
"FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n");
}
else // D3D
{
code.Write("cbuffer PSBlock : register(b0) {\n"
" int4 position;\n"
" float y_scale;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float3 filter_coefficients;\n"
"};\n"
"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n");
code.WriteFmt("cbuffer PSBlock : register(b0) {{\n"
" int4 position;\n"
" float y_scale;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float3 filter_coefficients;\n"
"}};\n"
"sampler samp0 : register(s0);\n"
"Texture2DArray Tex0 : register(t0);\n");
}
// D3D does not have roundEven(), only round(), which is specified "to the nearest integer".
// This differs from the roundEven() behavior, but to get consistency across drivers in OpenGL
// we need to use roundEven().
if (api_type == APIType::D3D)
code.Write("#define roundEven(x) round(x)\n");
code.WriteFmt("#define roundEven(x) round(x)\n");
// Alpha channel in the copy is set to 1 the EFB format does not have an alpha channel.
code.Write("float4 RGBA8ToRGB8(float4 src)\n"
"{\n"
" return float4(src.xyz, 1.0);\n"
"}\n"
code.WriteFmt("float4 RGBA8ToRGB8(float4 src)\n"
"{{\n"
" return float4(src.xyz, 1.0);\n"
"}}\n"
"float4 RGBA8ToRGBA6(float4 src)\n"
"{\n"
" int4 val = int4(roundEven(src * 255.0)) >> 2;\n"
" return float4(val) / 63.0;\n"
"}\n"
"float4 RGBA8ToRGBA6(float4 src)\n"
"{{\n"
" int4 val = int4(roundEven(src * 255.0)) >> 2;\n"
" return float4(val) / 63.0;\n"
"}}\n"
"float4 RGBA8ToRGB565(float4 src)\n"
"{\n"
" int4 val = int4(roundEven(src * 255.0));\n"
" val = int4(val.r >> 3, val.g >> 2, val.b >> 3, 1);\n"
" return float4(val) / float4(31.0, 63.0, 31.0, 1.0);\n"
"}\n");
"float4 RGBA8ToRGB565(float4 src)\n"
"{{\n"
" int4 val = int4(roundEven(src * 255.0));\n"
" val = int4(val.r >> 3, val.g >> 2, val.b >> 3, 1);\n"
" return float4(val) / float4(31.0, 63.0, 31.0, 1.0);\n"
"}}\n");
}
static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, APIType api_type)
@ -126,16 +127,16 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
switch (params.efb_format)
{
case PEControl::RGB8_Z24:
code.Write("RGBA8ToRGB8(");
code.WriteFmt("RGBA8ToRGB8(");
break;
case PEControl::RGBA6_Z24:
code.Write("RGBA8ToRGBA6(");
code.WriteFmt("RGBA8ToRGBA6(");
break;
case PEControl::RGB565_Z16:
code.Write("RGBA8ToRGB565(");
code.WriteFmt("RGBA8ToRGB565(");
break;
default:
code.Write("(");
code.WriteFmt("(");
break;
}
}
@ -143,63 +144,63 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
{
// Handle D3D depth inversion.
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
code.Write("1.0 - (");
code.WriteFmt("1.0 - (");
else
code.Write("(");
code.WriteFmt("(");
}
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
code.Write("texture(samp0, float3(");
code.WriteFmt("texture(samp0, float3(");
else
code.Write("Tex0.Sample(samp0, float3(");
code.WriteFmt("Tex0.Sample(samp0, float3(");
code.Write("uv.x + float(xoffset) * pixel_size.x, ");
code.WriteFmt("uv.x + float(xoffset) * pixel_size.x, ");
// Reverse the direction for OpenGL, since positive numbers are distance from the bottom row.
if (yoffset != 0)
{
if (api_type == APIType::OpenGL)
code.Write("clamp(uv.y - float(%d) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
code.WriteFmt("clamp(uv.y - float({}) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
else
code.Write("clamp(uv.y + float(%d) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
code.WriteFmt("clamp(uv.y + float({}) * pixel_size.y, clamp_tb.x, clamp_tb.y)", yoffset);
}
else
{
code.Write("uv.y");
code.WriteFmt("uv.y");
}
code.Write(", 0.0)))");
code.WriteFmt(", 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.
code.Write("float4 SampleEFB(float2 uv, float2 pixel_size, int xoffset)\n"
"{\n");
code.WriteFmt("float4 SampleEFB(float2 uv, float2 pixel_size, int xoffset)\n"
"{{\n");
if (params.copy_filter)
{
code.Write(" float4 prev_row = ");
code.WriteFmt(" float4 prev_row = ");
WriteSampleOp(-1);
code.Write(";\n"
" float4 current_row = ");
code.WriteFmt(";\n"
" float4 current_row = ");
WriteSampleOp(0);
code.Write(";\n"
" float4 next_row = ");
code.WriteFmt(";\n"
" float4 next_row = ");
WriteSampleOp(1);
code.Write(";\n"
" return float4(min(prev_row.rgb * filter_coefficients[0] +\n"
" current_row.rgb * filter_coefficients[1] +\n"
" next_row.rgb * filter_coefficients[2], \n"
" float3(1, 1, 1)), current_row.a);\n");
code.WriteFmt(";\n"
" return float4(min(prev_row.rgb * filter_coefficients[0] +\n"
" current_row.rgb * filter_coefficients[1] +\n"
" next_row.rgb * filter_coefficients[2], \n"
" float3(1, 1, 1)), current_row.a);\n");
}
else
{
code.Write(" float4 current_row = ");
code.WriteFmt(" float4 current_row = ");
WriteSampleOp(0);
code.Write(";\n"
"return float4(min(current_row.rgb * filter_coefficients[1], float3(1, 1, 1)),\n"
" current_row.a);\n");
code.WriteFmt(";\n"
"return float4(min(current_row.rgb * filter_coefficients[1], float3(1, 1, 1)),\n"
" current_row.a);\n");
}
code.Write("}\n");
code.WriteFmt("}}\n");
}
// Block dimensions : widthStride, heightStride
@ -212,101 +213,101 @@ static void WriteSwizzler(ShaderCode& code, const EFBCopyParams& params, EFBCopy
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
{
code.Write("void main()\n"
"{\n"
" int2 sampleUv;\n"
" int2 uv1 = int2(gl_FragCoord.xy);\n");
code.WriteFmt("void main()\n"
"{{\n"
" int2 sampleUv;\n"
" int2 uv1 = int2(gl_FragCoord.xy);\n");
}
else // D3D
{
code.Write("void main(\n"
" in float3 v_tex0 : TEXCOORD0,\n"
" in float4 rawpos : SV_Position,\n"
" out float4 ocol0 : SV_Target)\n"
"{\n"
" int2 sampleUv;\n"
" int2 uv1 = int2(rawpos.xy);\n");
code.WriteFmt("void main(\n"
" in float3 v_tex0 : TEXCOORD0,\n"
" in float4 rawpos : SV_Position,\n"
" out float4 ocol0 : SV_Target)\n"
"{{\n"
" int2 sampleUv;\n"
" int2 uv1 = int2(rawpos.xy);\n");
}
const int blkW = TexDecoder_GetEFBCopyBlockWidthInTexels(format);
const int blkH = TexDecoder_GetEFBCopyBlockHeightInTexels(format);
int samples = GetEncodedSampleCount(format);
code.Write(" int x_block_position = (uv1.x >> %d) << %d;\n", IntLog2(blkH * blkW / samples),
IntLog2(blkW));
code.Write(" int y_block_position = uv1.y << %d;\n", IntLog2(blkH));
code.WriteFmt(" int x_block_position = (uv1.x >> {}) << {};\n", IntLog2(blkH * blkW / samples),
IntLog2(blkW));
code.WriteFmt(" int y_block_position = uv1.y << {};\n", IntLog2(blkH));
if (samples == 1)
{
// With samples == 1, we write out pairs of blocks; one A8R8, one G8B8.
code.Write(" bool first = (uv1.x & %d) == 0;\n", blkH * blkW / 2);
code.WriteFmt(" bool first = (uv1.x & {}) == 0;\n", blkH * blkW / 2);
samples = 2;
}
code.Write(" int offset_in_block = uv1.x & %d;\n", (blkH * blkW / samples) - 1);
code.Write(" int y_offset_in_block = offset_in_block >> %d;\n", IntLog2(blkW / samples));
code.Write(" int x_offset_in_block = (offset_in_block & %d) << %d;\n", (blkW / samples) - 1,
IntLog2(samples));
code.WriteFmt(" int offset_in_block = uv1.x & {};\n", (blkH * blkW / samples) - 1);
code.WriteFmt(" int y_offset_in_block = offset_in_block >> {};\n", IntLog2(blkW / samples));
code.WriteFmt(" int x_offset_in_block = (offset_in_block & {}) << {};\n", (blkW / samples) - 1,
IntLog2(samples));
code.Write(" sampleUv.x = x_block_position + x_offset_in_block;\n"
" sampleUv.y = y_block_position + y_offset_in_block;\n");
code.WriteFmt(" sampleUv.x = x_block_position + x_offset_in_block;\n"
" sampleUv.y = y_block_position + y_offset_in_block;\n");
// sampleUv is the sample position in (int)gx_coords
code.Write(" float2 uv0 = float2(sampleUv);\n");
code.WriteFmt(" float2 uv0 = float2(sampleUv);\n");
// Move to center of pixel
code.Write(" uv0 += float2(0.5, 0.5);\n");
code.WriteFmt(" uv0 += float2(0.5, 0.5);\n");
// Scale by two if needed (also move to pixel borders
// so that linear filtering will average adjacent
// pixel)
code.Write(" uv0 *= float(position.w);\n");
code.WriteFmt(" uv0 *= float(position.w);\n");
// Move to copied rect
code.Write(" uv0 += float2(position.xy);\n");
code.WriteFmt(" uv0 += float2(position.xy);\n");
// Normalize to [0:1]
code.Write(" uv0 /= float2(%d, %d);\n", EFB_WIDTH, EFB_HEIGHT);
code.WriteFmt(" uv0 /= float2({}, {});\n", EFB_WIDTH, EFB_HEIGHT);
// Apply the y scaling
code.Write(" uv0 /= float2(1, y_scale);\n");
code.WriteFmt(" uv0 /= float2(1, y_scale);\n");
// OGL has to flip up and down
if (api_type == APIType::OpenGL)
{
code.Write(" uv0.y = 1.0-uv0.y;\n");
code.WriteFmt(" uv0.y = 1.0-uv0.y;\n");
}
code.Write(" float2 pixel_size = float2(position.w, position.w) / float2(%d, %d);\n", EFB_WIDTH,
EFB_HEIGHT);
code.WriteFmt(" float2 pixel_size = float2(position.w, position.w) / float2({}, {});\n",
EFB_WIDTH, EFB_HEIGHT);
}
static void WriteSampleColor(ShaderCode& code, const char* colorComp, const char* dest, int xoffset,
APIType api_type, const EFBCopyParams& params)
static void WriteSampleColor(ShaderCode& code, std::string_view color_comp, std::string_view dest,
int x_offset, APIType api_type, const EFBCopyParams& params)
{
code.Write(" %s = SampleEFB(uv0, pixel_size, %d).%s;\n", dest, xoffset, colorComp);
code.WriteFmt(" {} = SampleEFB(uv0, pixel_size, {}).{};\n", dest, x_offset, color_comp);
}
static void WriteColorToIntensity(ShaderCode& code, const char* src, const char* dest)
static void WriteColorToIntensity(ShaderCode& code, std::string_view src, std::string_view dest)
{
if (!IntensityConstantAdded)
{
code.Write(" float4 IntensityConst = float4(0.257f,0.504f,0.098f,0.0625f);\n");
code.WriteFmt(" float4 IntensityConst = float4(0.257f,0.504f,0.098f,0.0625f);\n");
IntensityConstantAdded = true;
}
code.Write(" %s = dot(IntensityConst.rgb, %s.rgb);\n", dest, src);
code.WriteFmt(" {} = dot(IntensityConst.rgb, {}.rgb);\n", dest, src);
// don't add IntensityConst.a yet, because doing it later is faster and uses less instructions,
// due to vectorization
}
static void WriteToBitDepth(ShaderCode& code, u8 depth, const char* src, const char* dest)
static void WriteToBitDepth(ShaderCode& code, u8 depth, std::string_view src, std::string_view dest)
{
code.Write(" %s = floor(%s * 255.0 / exp2(8.0 - %d.0));\n", dest, src, depth);
code.WriteFmt(" {} = floor({} * 255.0 / exp2(8.0 - {}.0));\n", dest, src, depth);
}
static void WriteEncoderEnd(ShaderCode& code)
{
code.Write("}\n");
code.WriteFmt("}}\n");
IntensityConstantAdded = false;
}
static void WriteI8Encoder(ShaderCode& code, APIType api_type, const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::R8, api_type);
code.Write(" float3 texSample;\n");
code.WriteFmt(" float3 texSample;\n");
WriteSampleColor(code, "rgb", "texSample", 0, api_type, params);
WriteColorToIntensity(code, "texSample", "ocol0.b");
@ -321,7 +322,7 @@ static void WriteI8Encoder(ShaderCode& code, APIType api_type, const EFBCopyPara
WriteColorToIntensity(code, "texSample", "ocol0.a");
// See WriteColorToIntensity
code.Write(" ocol0.rgba += IntensityConst.aaaa;\n");
code.WriteFmt(" ocol0.rgba += IntensityConst.aaaa;\n");
WriteEncoderEnd(code);
}
@ -329,9 +330,9 @@ static void WriteI8Encoder(ShaderCode& code, APIType api_type, const EFBCopyPara
static void WriteI4Encoder(ShaderCode& code, APIType api_type, const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::R4, api_type);
code.Write(" float3 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
code.WriteFmt(" float3 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
WriteSampleColor(code, "rgb", "texSample", 0, api_type, params);
WriteColorToIntensity(code, "texSample", "color0.b");
@ -357,30 +358,30 @@ static void WriteI4Encoder(ShaderCode& code, APIType api_type, const EFBCopyPara
WriteSampleColor(code, "rgb", "texSample", 7, api_type, params);
WriteColorToIntensity(code, "texSample", "color1.a");
code.Write(" color0.rgba += IntensityConst.aaaa;\n"
" color1.rgba += IntensityConst.aaaa;\n");
code.WriteFmt(" color0.rgba += IntensityConst.aaaa;\n"
" color1.rgba += IntensityConst.aaaa;\n");
WriteToBitDepth(code, 4, "color0", "color0");
WriteToBitDepth(code, 4, "color1", "color1");
code.Write(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
code.WriteFmt(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
WriteEncoderEnd(code);
}
static void WriteIA8Encoder(ShaderCode& code, APIType api_type, const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::RA8, api_type);
code.Write(" float4 texSample;\n");
code.WriteFmt(" float4 texSample;\n");
WriteSampleColor(code, "rgba", "texSample", 0, api_type, params);
code.Write(" ocol0.b = texSample.a;\n");
code.WriteFmt(" ocol0.b = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "ocol0.g");
WriteSampleColor(code, "rgba", "texSample", 1, api_type, params);
code.Write(" ocol0.r = texSample.a;\n");
code.WriteFmt(" ocol0.r = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "ocol0.a");
code.Write(" ocol0.ga += IntensityConst.aa;\n");
code.WriteFmt(" ocol0.ga += IntensityConst.aa;\n");
WriteEncoderEnd(code);
}
@ -388,57 +389,57 @@ static void WriteIA8Encoder(ShaderCode& code, APIType api_type, const EFBCopyPar
static void WriteIA4Encoder(ShaderCode& code, APIType api_type, const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::RA4, api_type);
code.Write(" float4 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
code.WriteFmt(" float4 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
WriteSampleColor(code, "rgba", "texSample", 0, api_type, params);
code.Write(" color0.b = texSample.a;\n");
code.WriteFmt(" color0.b = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "color1.b");
WriteSampleColor(code, "rgba", "texSample", 1, api_type, params);
code.Write(" color0.g = texSample.a;\n");
code.WriteFmt(" color0.g = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "color1.g");
WriteSampleColor(code, "rgba", "texSample", 2, api_type, params);
code.Write(" color0.r = texSample.a;\n");
code.WriteFmt(" color0.r = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "color1.r");
WriteSampleColor(code, "rgba", "texSample", 3, api_type, params);
code.Write(" color0.a = texSample.a;\n");
code.WriteFmt(" color0.a = texSample.a;\n");
WriteColorToIntensity(code, "texSample", "color1.a");
code.Write(" color1.rgba += IntensityConst.aaaa;\n");
code.WriteFmt(" color1.rgba += IntensityConst.aaaa;\n");
WriteToBitDepth(code, 4, "color0", "color0");
WriteToBitDepth(code, 4, "color1", "color1");
code.Write(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
code.WriteFmt(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
WriteEncoderEnd(code);
}
static void WriteRGB565Encoder(ShaderCode& code, APIType api_type, const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::RGB565, api_type);
code.Write(" float3 texSample0;\n"
" float3 texSample1;\n");
code.WriteFmt(" float3 texSample0;\n"
" float3 texSample1;\n");
WriteSampleColor(code, "rgb", "texSample0", 0, api_type, params);
WriteSampleColor(code, "rgb", "texSample1", 1, api_type, params);
code.Write(" float2 texRs = float2(texSample0.r, texSample1.r);\n"
" float2 texGs = float2(texSample0.g, texSample1.g);\n"
" float2 texBs = float2(texSample0.b, texSample1.b);\n");
code.WriteFmt(" float2 texRs = float2(texSample0.r, texSample1.r);\n"
" float2 texGs = float2(texSample0.g, texSample1.g);\n"
" float2 texBs = float2(texSample0.b, texSample1.b);\n");
WriteToBitDepth(code, 6, "texGs", "float2 gInt");
code.Write(" float2 gUpper = floor(gInt / 8.0);\n"
" float2 gLower = gInt - gUpper * 8.0;\n");
code.WriteFmt(" float2 gUpper = floor(gInt / 8.0);\n"
" float2 gLower = gInt - gUpper * 8.0;\n");
WriteToBitDepth(code, 5, "texRs", "ocol0.br");
code.Write(" ocol0.br = ocol0.br * 8.0 + gUpper;\n");
code.WriteFmt(" ocol0.br = ocol0.br * 8.0 + gUpper;\n");
WriteToBitDepth(code, 5, "texBs", "ocol0.ga");
code.Write(" ocol0.ga = ocol0.ga + gLower * 32.0;\n");
code.WriteFmt(" ocol0.ga = ocol0.ga + gLower * 32.0;\n");
code.Write(" ocol0 = ocol0 / 255.0;\n");
code.WriteFmt(" ocol0 = ocol0 / 255.0;\n");
WriteEncoderEnd(code);
}
@ -446,63 +447,63 @@ static void WriteRGB5A3Encoder(ShaderCode& code, APIType api_type, const EFBCopy
{
WriteSwizzler(code, params, EFBCopyFormat::RGB5A3, api_type);
code.Write(" float4 texSample;\n"
" float color0;\n"
" float gUpper;\n"
" float gLower;\n");
code.WriteFmt(" float4 texSample;\n"
" float color0;\n"
" float gUpper;\n"
" float gLower;\n");
WriteSampleColor(code, "rgba", "texSample", 0, api_type, params);
// 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits
code.Write("if(texSample.a > 0.878f) {\n");
code.WriteFmt("if(texSample.a > 0.878f) {{\n");
WriteToBitDepth(code, 5, "texSample.g", "color0");
code.Write(" gUpper = floor(color0 / 8.0);\n"
" gLower = color0 - gUpper * 8.0;\n");
code.WriteFmt(" gUpper = floor(color0 / 8.0);\n"
" gLower = color0 - gUpper * 8.0;\n");
WriteToBitDepth(code, 5, "texSample.r", "ocol0.b");
code.Write(" ocol0.b = ocol0.b * 4.0 + gUpper + 128.0;\n");
code.WriteFmt(" ocol0.b = ocol0.b * 4.0 + gUpper + 128.0;\n");
WriteToBitDepth(code, 5, "texSample.b", "ocol0.g");
code.Write(" ocol0.g = ocol0.g + gLower * 32.0;\n");
code.WriteFmt(" ocol0.g = ocol0.g + gLower * 32.0;\n");
code.Write("} else {\n");
code.WriteFmt("}} else {{\n");
WriteToBitDepth(code, 4, "texSample.r", "ocol0.b");
WriteToBitDepth(code, 4, "texSample.b", "ocol0.g");
WriteToBitDepth(code, 3, "texSample.a", "color0");
code.Write("ocol0.b = ocol0.b + color0 * 16.0;\n");
code.WriteFmt("ocol0.b = ocol0.b + color0 * 16.0;\n");
WriteToBitDepth(code, 4, "texSample.g", "color0");
code.Write("ocol0.g = ocol0.g + color0 * 16.0;\n");
code.WriteFmt("ocol0.g = ocol0.g + color0 * 16.0;\n");
code.Write("}\n");
code.WriteFmt("}}\n");
WriteSampleColor(code, "rgba", "texSample", 1, api_type, params);
code.Write("if(texSample.a > 0.878f) {\n");
code.WriteFmt("if(texSample.a > 0.878f) {{\n");
WriteToBitDepth(code, 5, "texSample.g", "color0");
code.Write(" gUpper = floor(color0 / 8.0);\n"
" gLower = color0 - gUpper * 8.0;\n");
code.WriteFmt(" gUpper = floor(color0 / 8.0);\n"
" gLower = color0 - gUpper * 8.0;\n");
WriteToBitDepth(code, 5, "texSample.r", "ocol0.r");
code.Write(" ocol0.r = ocol0.r * 4.0 + gUpper + 128.0;\n");
code.WriteFmt(" ocol0.r = ocol0.r * 4.0 + gUpper + 128.0;\n");
WriteToBitDepth(code, 5, "texSample.b", "ocol0.a");
code.Write(" ocol0.a = ocol0.a + gLower * 32.0;\n");
code.WriteFmt(" ocol0.a = ocol0.a + gLower * 32.0;\n");
code.Write("} else {\n");
code.WriteFmt("}} else {{\n");
WriteToBitDepth(code, 4, "texSample.r", "ocol0.r");
WriteToBitDepth(code, 4, "texSample.b", "ocol0.a");
WriteToBitDepth(code, 3, "texSample.a", "color0");
code.Write("ocol0.r = ocol0.r + color0 * 16.0;\n");
code.WriteFmt("ocol0.r = ocol0.r + color0 * 16.0;\n");
WriteToBitDepth(code, 4, "texSample.g", "color0");
code.Write("ocol0.a = ocol0.a + color0 * 16.0;\n");
code.WriteFmt("ocol0.a = ocol0.a + color0 * 16.0;\n");
code.Write("}\n");
code.WriteFmt("}}\n");
code.Write(" ocol0 = ocol0 / 255.0;\n");
code.WriteFmt(" ocol0 = ocol0 / 255.0;\n");
WriteEncoderEnd(code);
}
@ -510,33 +511,33 @@ static void WriteRGBA8Encoder(ShaderCode& code, APIType api_type, const EFBCopyP
{
WriteSwizzler(code, params, EFBCopyFormat::RGBA8, api_type);
code.Write(" float4 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
code.WriteFmt(" float4 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
WriteSampleColor(code, "rgba", "texSample", 0, api_type, params);
code.Write(" color0.b = texSample.a;\n"
" color0.g = texSample.r;\n"
" color1.b = texSample.g;\n"
" color1.g = texSample.b;\n");
code.WriteFmt(" color0.b = texSample.a;\n"
" color0.g = texSample.r;\n"
" color1.b = texSample.g;\n"
" color1.g = texSample.b;\n");
WriteSampleColor(code, "rgba", "texSample", 1, api_type, params);
code.Write(" color0.r = texSample.a;\n"
" color0.a = texSample.r;\n"
" color1.r = texSample.g;\n"
" color1.a = texSample.b;\n");
code.WriteFmt(" color0.r = texSample.a;\n"
" color0.a = texSample.r;\n"
" color1.r = texSample.g;\n"
" color1.a = texSample.b;\n");
code.Write(" ocol0 = first ? color0 : color1;\n");
code.WriteFmt(" ocol0 = first ? color0 : color1;\n");
WriteEncoderEnd(code);
}
static void WriteC4Encoder(ShaderCode& code, const char* comp, APIType api_type,
static void WriteC4Encoder(ShaderCode& code, std::string_view comp, APIType api_type,
const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::R4, api_type);
code.Write(" float4 color0;\n"
" float4 color1;\n");
code.WriteFmt(" float4 color0;\n"
" float4 color1;\n");
WriteSampleColor(code, comp, "color0.b", 0, api_type, params);
WriteSampleColor(code, comp, "color1.b", 1, api_type, params);
@ -550,11 +551,11 @@ static void WriteC4Encoder(ShaderCode& code, const char* comp, APIType api_type,
WriteToBitDepth(code, 4, "color0", "color0");
WriteToBitDepth(code, 4, "color1", "color1");
code.Write(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
code.WriteFmt(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
WriteEncoderEnd(code);
}
static void WriteC8Encoder(ShaderCode& code, const char* comp, APIType api_type,
static void WriteC8Encoder(ShaderCode& code, std::string_view comp, APIType api_type,
const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::R8, api_type);
@ -567,38 +568,38 @@ static void WriteC8Encoder(ShaderCode& code, const char* comp, APIType api_type,
WriteEncoderEnd(code);
}
static void WriteCC4Encoder(ShaderCode& code, const char* comp, APIType api_type,
static void WriteCC4Encoder(ShaderCode& code, std::string_view comp, APIType api_type,
const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::RA4, api_type);
code.Write(" float2 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
code.WriteFmt(" float2 texSample;\n"
" float4 color0;\n"
" float4 color1;\n");
WriteSampleColor(code, comp, "texSample", 0, api_type, params);
code.Write(" color0.b = texSample.x;\n"
" color1.b = texSample.y;\n");
code.WriteFmt(" color0.b = texSample.x;\n"
" color1.b = texSample.y;\n");
WriteSampleColor(code, comp, "texSample", 1, api_type, params);
code.Write(" color0.g = texSample.x;\n"
" color1.g = texSample.y;\n");
code.WriteFmt(" color0.g = texSample.x;\n"
" color1.g = texSample.y;\n");
WriteSampleColor(code, comp, "texSample", 2, api_type, params);
code.Write(" color0.r = texSample.x;\n"
" color1.r = texSample.y;\n");
code.WriteFmt(" color0.r = texSample.x;\n"
" color1.r = texSample.y;\n");
WriteSampleColor(code, comp, "texSample", 3, api_type, params);
code.Write(" color0.a = texSample.x;\n"
" color1.a = texSample.y;\n");
code.WriteFmt(" color0.a = texSample.x;\n"
" color1.a = texSample.y;\n");
WriteToBitDepth(code, 4, "color0", "color0");
WriteToBitDepth(code, 4, "color1", "color1");
code.Write(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
code.WriteFmt(" ocol0 = (color0 * 16.0 + color1) / 255.0;\n");
WriteEncoderEnd(code);
}
static void WriteCC8Encoder(ShaderCode& code, const char* comp, APIType api_type,
static void WriteCC8Encoder(ShaderCode& code, std::string_view comp, APIType api_type,
const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::RA8, api_type);
@ -609,24 +610,24 @@ static void WriteCC8Encoder(ShaderCode& code, const char* comp, APIType api_type
WriteEncoderEnd(code);
}
static void WriteZ8Encoder(ShaderCode& code, const char* multiplier, APIType api_type,
static void WriteZ8Encoder(ShaderCode& code, std::string_view multiplier, APIType api_type,
const EFBCopyParams& params)
{
WriteSwizzler(code, params, EFBCopyFormat::G8, api_type);
code.Write(" float depth;\n");
code.WriteFmt(" float depth;\n");
WriteSampleColor(code, "r", "depth", 0, api_type, params);
code.Write("ocol0.b = frac(depth * %s);\n", multiplier);
code.WriteFmt("ocol0.b = frac(depth * {});\n", multiplier);
WriteSampleColor(code, "r", "depth", 1, api_type, params);
code.Write("ocol0.g = frac(depth * %s);\n", multiplier);
code.WriteFmt("ocol0.g = frac(depth * {});\n", multiplier);
WriteSampleColor(code, "r", "depth", 2, api_type, params);
code.Write("ocol0.r = frac(depth * %s);\n", multiplier);
code.WriteFmt("ocol0.r = frac(depth * {});\n", multiplier);
WriteSampleColor(code, "r", "depth", 3, api_type, params);
code.Write("ocol0.a = frac(depth * %s);\n", multiplier);
code.WriteFmt("ocol0.a = frac(depth * {});\n", multiplier);
WriteEncoderEnd(code);
}
@ -635,30 +636,30 @@ static void WriteZ16Encoder(ShaderCode& code, APIType api_type, const EFBCopyPar
{
WriteSwizzler(code, params, EFBCopyFormat::RA8, api_type);
code.Write(" float depth;\n"
" float3 expanded;\n");
code.WriteFmt(" float depth;\n"
" float3 expanded;\n");
// Byte order is reversed
WriteSampleColor(code, "r", "depth", 0, api_type, params);
code.Write(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n");
code.WriteFmt(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n");
code.Write(" ocol0.b = expanded.g / 255.0;\n"
" ocol0.g = expanded.r / 255.0;\n");
code.WriteFmt(" ocol0.b = expanded.g / 255.0;\n"
" ocol0.g = expanded.r / 255.0;\n");
WriteSampleColor(code, "r", "depth", 1, api_type, params);
code.Write(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n");
code.WriteFmt(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n");
code.Write(" ocol0.r = expanded.g / 255.0;\n"
" ocol0.a = expanded.r / 255.0;\n");
code.WriteFmt(" ocol0.r = expanded.g / 255.0;\n"
" ocol0.a = expanded.r / 255.0;\n");
WriteEncoderEnd(code);
}
@ -667,34 +668,34 @@ static void WriteZ16LEncoder(ShaderCode& code, APIType api_type, const EFBCopyPa
{
WriteSwizzler(code, params, EFBCopyFormat::GB8, api_type);
code.Write(" float depth;\n"
" float3 expanded;\n");
code.WriteFmt(" float depth;\n"
" float3 expanded;\n");
// Byte order is reversed
WriteSampleColor(code, "r", "depth", 0, api_type, params);
code.Write(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n"
" depth -= expanded.g * 256.0;\n"
" expanded.b = depth;\n");
code.WriteFmt(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n"
" depth -= expanded.g * 256.0;\n"
" expanded.b = depth;\n");
code.Write(" ocol0.b = expanded.b / 255.0;\n"
" ocol0.g = expanded.g / 255.0;\n");
code.WriteFmt(" ocol0.b = expanded.b / 255.0;\n"
" ocol0.g = expanded.g / 255.0;\n");
WriteSampleColor(code, "r", "depth", 1, api_type, params);
code.Write(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n"
" depth -= expanded.g * 256.0;\n"
" expanded.b = depth;\n");
code.WriteFmt(" depth *= 16777216.0;\n"
" expanded.r = floor(depth / (256.0 * 256.0));\n"
" depth -= expanded.r * 256.0 * 256.0;\n"
" expanded.g = floor(depth / 256.0);\n"
" depth -= expanded.g * 256.0;\n"
" expanded.b = depth;\n");
code.Write(" ocol0.r = expanded.b / 255.0;\n"
" ocol0.a = expanded.g / 255.0;\n");
code.WriteFmt(" ocol0.r = expanded.b / 255.0;\n"
" ocol0.a = expanded.g / 255.0;\n");
WriteEncoderEnd(code);
}
@ -703,38 +704,38 @@ static void WriteZ24Encoder(ShaderCode& code, APIType api_type, const EFBCopyPar
{
WriteSwizzler(code, params, EFBCopyFormat::RGBA8, api_type);
code.Write(" float depth0;\n"
" float depth1;\n"
" float3 expanded0;\n"
" float3 expanded1;\n");
code.WriteFmt(" float depth0;\n"
" float depth1;\n"
" float3 expanded0;\n"
" float3 expanded1;\n");
WriteSampleColor(code, "r", "depth0", 0, api_type, params);
WriteSampleColor(code, "r", "depth1", 1, api_type, params);
for (int i = 0; i < 2; i++)
{
code.Write(" depth%i *= 16777216.0;\n", i);
code.WriteFmt(" depth{} *= 16777216.0;\n", i);
code.Write(" expanded%i.r = floor(depth%i / (256.0 * 256.0));\n", i, i);
code.Write(" depth%i -= expanded%i.r * 256.0 * 256.0;\n", i, i);
code.Write(" expanded%i.g = floor(depth%i / 256.0);\n", i, i);
code.Write(" depth%i -= expanded%i.g * 256.0;\n", i, i);
code.Write(" expanded%i.b = depth%i;\n", i, i);
code.WriteFmt(" expanded{}.r = floor(depth{} / (256.0 * 256.0));\n", i, i);
code.WriteFmt(" depth{} -= expanded{}.r * 256.0 * 256.0;\n", i, i);
code.WriteFmt(" expanded{}.g = floor(depth{} / 256.0);\n", i, i);
code.WriteFmt(" depth{} -= expanded{}.g * 256.0;\n", i, i);
code.WriteFmt(" expanded{}.b = depth{};\n", i, i);
}
code.Write(" if (!first) {\n");
code.WriteFmt(" if (!first) {{\n");
// Upper 16
code.Write(" ocol0.b = expanded0.g / 255.0;\n"
" ocol0.g = expanded0.b / 255.0;\n"
" ocol0.r = expanded1.g / 255.0;\n"
" ocol0.a = expanded1.b / 255.0;\n"
" } else {\n");
code.WriteFmt(" ocol0.b = expanded0.g / 255.0;\n"
" ocol0.g = expanded0.b / 255.0;\n"
" ocol0.r = expanded1.g / 255.0;\n"
" ocol0.a = expanded1.b / 255.0;\n"
" }} else {{\n");
// Lower 8
code.Write(" ocol0.b = 1.0;\n"
" ocol0.g = expanded0.r / 255.0;\n"
" ocol0.r = 1.0;\n"
" ocol0.a = expanded1.r / 255.0;\n"
" }\n");
code.WriteFmt(" ocol0.b = 1.0;\n"
" ocol0.g = expanded0.r / 255.0;\n"
" ocol0.r = 1.0;\n"
" ocol0.a = expanded1.r / 255.0;\n"
" }}\n");
WriteEncoderEnd(code);
}
@ -743,23 +744,23 @@ static void WriteXFBEncoder(ShaderCode& code, APIType api_type, const EFBCopyPar
{
WriteSwizzler(code, params, EFBCopyFormat::XFB, api_type);
code.Write("float3 color0, color1;\n");
code.WriteFmt("float3 color0, color1;\n");
WriteSampleColor(code, "rgb", "color0", 0, api_type, params);
WriteSampleColor(code, "rgb", "color1", 1, api_type, params);
// Gamma is only applied to XFB copies.
code.Write(" color0 = pow(color0, float3(gamma_rcp, gamma_rcp, gamma_rcp));\n"
" color1 = pow(color1, float3(gamma_rcp, gamma_rcp, gamma_rcp));\n");
code.WriteFmt(" color0 = pow(color0, float3(gamma_rcp, gamma_rcp, gamma_rcp));\n"
" color1 = pow(color1, float3(gamma_rcp, gamma_rcp, gamma_rcp));\n");
// Convert to YUV.
code.Write(" const float3 y_const = float3(0.257, 0.504, 0.098);\n"
" const float3 u_const = float3(-0.148, -0.291, 0.439);\n"
" const float3 v_const = float3(0.439, -0.368, -0.071);\n"
" float3 average = (color0 + color1) * 0.5;\n"
" ocol0.b = dot(color0, y_const) + 0.0625;\n"
" ocol0.g = dot(average, u_const) + 0.5;\n"
" ocol0.r = dot(color1, y_const) + 0.0625;\n"
" ocol0.a = dot(average, v_const) + 0.5;\n");
code.WriteFmt(" const float3 y_const = float3(0.257, 0.504, 0.098);\n"
" const float3 u_const = float3(-0.148, -0.291, 0.439);\n"
" const float3 v_const = float3(0.439, -0.368, -0.071);\n"
" float3 average = (color0 + color1) * 0.5;\n"
" ocol0.b = dot(color0, y_const) + 0.0625;\n"
" ocol0.g = dot(average, u_const) + 0.5;\n"
" ocol0.r = dot(color1, y_const) + 0.0625;\n"
" ocol0.a = dot(average, v_const) + 0.5;\n");
WriteEncoderEnd(code);
}