diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index 5d19ad9b34..fefcce0d1d 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -6,6 +6,7 @@ #include #include +#include #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); }