diff options
Diffstat (limited to 'Source/Core/VideoCommon/PixelShaderGen.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/PixelShaderGen.cpp | 645 |
1 files changed, 317 insertions, 328 deletions
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 8d4abb704f..288761af8e 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -365,98 +365,98 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type, u32 num_tex const ShaderHostConfig& host_config, bool bounding_box) { // dot product for integer vectors - out.WriteFmt("int idot(int3 x, int3 y)\n" - "{{\n" - "\tint3 tmp = x * y;\n" - "\treturn tmp.x + tmp.y + tmp.z;\n" - "}}\n"); - - out.WriteFmt("int idot(int4 x, int4 y)\n" - "{{\n" - "\tint4 tmp = x * y;\n" - "\treturn tmp.x + tmp.y + tmp.z + tmp.w;\n" - "}}\n\n"); + out.Write("int idot(int3 x, int3 y)\n" + "{{\n" + "\tint3 tmp = x * y;\n" + "\treturn tmp.x + tmp.y + tmp.z;\n" + "}}\n"); + + out.Write("int idot(int4 x, int4 y)\n" + "{{\n" + "\tint4 tmp = x * y;\n" + "\treturn tmp.x + tmp.y + tmp.z + tmp.w;\n" + "}}\n\n"); // rounding + casting to integer at once in a single function - out.WriteFmt("int iround(float x) {{ return int (round(x)); }}\n" - "int2 iround(float2 x) {{ return int2(round(x)); }}\n" - "int3 iround(float3 x) {{ return int3(round(x)); }}\n" - "int4 iround(float4 x) {{ return int4(round(x)); }}\n\n"); + out.Write("int iround(float x) {{ return int (round(x)); }}\n" + "int2 iround(float2 x) {{ return int2(round(x)); }}\n" + "int3 iround(float3 x) {{ return int3(round(x)); }}\n" + "int4 iround(float4 x) {{ return int4(round(x)); }}\n\n"); if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) { - out.WriteFmt("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n"); + out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n"); } else // D3D { // Declare samplers - out.WriteFmt("SamplerState samp[8] : register(s0);\n" - "\n" - "Texture2DArray Tex[8] : register(t0);\n"); + out.Write("SamplerState samp[8] : register(s0);\n" + "\n" + "Texture2DArray Tex[8] : register(t0);\n"); } - out.WriteFmt("\n"); + out.Write("\n"); if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) - out.WriteFmt("UBO_BINDING(std140, 1) uniform PSBlock {{\n"); + out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"); else - out.WriteFmt("cbuffer PSBlock : register(b0) {{\n"); - - out.WriteFmt("\tint4 " I_COLORS "[4];\n" - "\tint4 " I_KCOLORS "[4];\n" - "\tint4 " I_ALPHA ";\n" - "\tfloat4 " I_TEXDIMS "[8];\n" - "\tint4 " I_ZBIAS "[2];\n" - "\tint4 " I_INDTEXSCALE "[2];\n" - "\tint4 " I_INDTEXMTX "[6];\n" - "\tint4 " I_FOGCOLOR ";\n" - "\tint4 " I_FOGI ";\n" - "\tfloat4 " I_FOGF ";\n" - "\tfloat4 " I_FOGRANGE "[3];\n" - "\tfloat4 " I_ZSLOPE ";\n" - "\tfloat2 " I_EFBSCALE ";\n" - "\tuint bpmem_genmode;\n" - "\tuint bpmem_alphaTest;\n" - "\tuint bpmem_fogParam3;\n" - "\tuint bpmem_fogRangeBase;\n" - "\tuint bpmem_dstalpha;\n" - "\tuint bpmem_ztex_op;\n" - "\tbool bpmem_late_ztest;\n" - "\tbool bpmem_rgba6_format;\n" - "\tbool bpmem_dither;\n" - "\tbool bpmem_bounding_box;\n" - "\tuint4 bpmem_pack1[16];\n" // .xy - combiners, .z - tevind - "\tuint4 bpmem_pack2[8];\n" // .x - tevorder, .y - tevksel - "\tint4 konstLookup[32];\n" - "\tbool blend_enable;\n" - "\tuint blend_src_factor;\n" - "\tuint blend_src_factor_alpha;\n" - "\tuint blend_dst_factor;\n" - "\tuint blend_dst_factor_alpha;\n" - "\tbool blend_subtract;\n" - "\tbool blend_subtract_alpha;\n" - "}};\n\n"); - out.WriteFmt("#define bpmem_combiners(i) (bpmem_pack1[(i)].xy)\n" - "#define bpmem_tevind(i) (bpmem_pack1[(i)].z)\n" - "#define bpmem_iref(i) (bpmem_pack1[(i)].w)\n" - "#define bpmem_tevorder(i) (bpmem_pack2[(i)].x)\n" - "#define bpmem_tevksel(i) (bpmem_pack2[(i)].y)\n\n"); + out.Write("cbuffer PSBlock : register(b0) {{\n"); + + out.Write("\tint4 " I_COLORS "[4];\n" + "\tint4 " I_KCOLORS "[4];\n" + "\tint4 " I_ALPHA ";\n" + "\tfloat4 " I_TEXDIMS "[8];\n" + "\tint4 " I_ZBIAS "[2];\n" + "\tint4 " I_INDTEXSCALE "[2];\n" + "\tint4 " I_INDTEXMTX "[6];\n" + "\tint4 " I_FOGCOLOR ";\n" + "\tint4 " I_FOGI ";\n" + "\tfloat4 " I_FOGF ";\n" + "\tfloat4 " I_FOGRANGE "[3];\n" + "\tfloat4 " I_ZSLOPE ";\n" + "\tfloat2 " I_EFBSCALE ";\n" + "\tuint bpmem_genmode;\n" + "\tuint bpmem_alphaTest;\n" + "\tuint bpmem_fogParam3;\n" + "\tuint bpmem_fogRangeBase;\n" + "\tuint bpmem_dstalpha;\n" + "\tuint bpmem_ztex_op;\n" + "\tbool bpmem_late_ztest;\n" + "\tbool bpmem_rgba6_format;\n" + "\tbool bpmem_dither;\n" + "\tbool bpmem_bounding_box;\n" + "\tuint4 bpmem_pack1[16];\n" // .xy - combiners, .z - tevind + "\tuint4 bpmem_pack2[8];\n" // .x - tevorder, .y - tevksel + "\tint4 konstLookup[32];\n" + "\tbool blend_enable;\n" + "\tuint blend_src_factor;\n" + "\tuint blend_src_factor_alpha;\n" + "\tuint blend_dst_factor;\n" + "\tuint blend_dst_factor_alpha;\n" + "\tbool blend_subtract;\n" + "\tbool blend_subtract_alpha;\n" + "}};\n\n"); + out.Write("#define bpmem_combiners(i) (bpmem_pack1[(i)].xy)\n" + "#define bpmem_tevind(i) (bpmem_pack1[(i)].z)\n" + "#define bpmem_iref(i) (bpmem_pack1[(i)].w)\n" + "#define bpmem_tevorder(i) (bpmem_pack2[(i)].x)\n" + "#define bpmem_tevksel(i) (bpmem_pack2[(i)].y)\n\n"); if (host_config.per_pixel_lighting) { - out.WriteFmt("{}", s_lighting_struct); + out.Write("{}", s_lighting_struct); if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) - out.WriteFmt("UBO_BINDING(std140, 2) uniform VSBlock {{\n"); + out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n"); else - out.WriteFmt("cbuffer VSBlock : register(b1) {{\n"); + out.Write("cbuffer VSBlock : register(b1) {{\n"); - out.WriteFmt("{}", s_shader_uniforms); - out.WriteFmt("}};\n"); + out.Write("{}", s_shader_uniforms); + out.Write("}};\n"); } if (bounding_box) { - out.WriteFmt(R"( + out.Write(R"( #ifdef API_D3D globallycoherent RWBuffer<int> bbox_data : register(u2); #define atomicMin InterlockedMin @@ -541,9 +541,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos const bool stereo = host_config.stereo; const u32 numStages = uid_data->genMode_numtevstages + 1; - out.WriteFmt("// Pixel Shader for TEV stages\n"); - out.WriteFmt("// {} TEV stages, {} texgens, {} IND stages\n", numStages, - uid_data->genMode_numtexgens, uid_data->genMode_numindstages); + out.Write("// Pixel Shader for TEV stages\n"); + out.Write("// {} TEV stages, {} texgens, {} IND stages\n", numStages, + uid_data->genMode_numtexgens, uid_data->genMode_numindstages); // Stuff that is shared between ubershaders and pixelgen. WritePixelShaderCommonHeader(out, api_type, uid_data->genMode_numtexgens, host_config, @@ -588,11 +588,11 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) { // This is a #define which signals whatever early-z method the driver supports. - out.WriteFmt("FORCE_EARLY_Z; \n"); + out.Write("FORCE_EARLY_Z; \n"); } else { - out.WriteFmt("[earlydepthstencil]\n"); + out.Write("[earlydepthstencil]\n"); } } @@ -610,13 +610,13 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos { if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION)) { - out.WriteFmt("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n" - "FRAGMENT_OUTPUT_LOCATION(1) out vec4 ocol1;\n"); + out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n" + "FRAGMENT_OUTPUT_LOCATION(1) out vec4 ocol1;\n"); } else { - out.WriteFmt("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 ocol0;\n" - "FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n"); + out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 ocol0;\n" + "FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n"); } } else if (use_shader_blend) @@ -627,142 +627,141 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // shader if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION)) { - out.WriteFmt("FRAGMENT_OUTPUT_LOCATION(0) FRAGMENT_INOUT vec4 real_ocol0;\n"); + out.Write("FRAGMENT_OUTPUT_LOCATION(0) FRAGMENT_INOUT vec4 real_ocol0;\n"); } else { - out.WriteFmt("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) FRAGMENT_INOUT vec4 real_ocol0;\n"); + out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) FRAGMENT_INOUT vec4 real_ocol0;\n"); } } else { - out.WriteFmt("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"); + out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"); } if (uid_data->per_pixel_depth) - out.WriteFmt("#define depth gl_FragDepth\n"); + out.Write("#define depth gl_FragDepth\n"); if (host_config.backend_geometry_shaders) { - out.WriteFmt("VARYING_LOCATION(0) in VertexData {{\n"); + out.Write("VARYING_LOCATION(0) in VertexData {{\n"); GenerateVSOutputMembers(out, api_type, uid_data->genMode_numtexgens, host_config, GetInterpolationQualifier(msaa, ssaa, true, true)); if (stereo) - out.WriteFmt("\tflat int layer;\n"); + out.Write("\tflat int layer;\n"); - out.WriteFmt("}};\n"); + out.Write("}};\n"); } else { // Let's set up attributes u32 counter = 0; - out.WriteFmt("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++, - GetInterpolationQualifier(msaa, ssaa)); - out.WriteFmt("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++, - GetInterpolationQualifier(msaa, ssaa)); + out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++, + GetInterpolationQualifier(msaa, ssaa)); + out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++, + GetInterpolationQualifier(msaa, ssaa)); for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i) { - out.WriteFmt("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++, - GetInterpolationQualifier(msaa, ssaa), i); + out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++, + GetInterpolationQualifier(msaa, ssaa), i); } if (!host_config.fast_depth_calc) { - out.WriteFmt("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++, - GetInterpolationQualifier(msaa, ssaa)); + out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++, + GetInterpolationQualifier(msaa, ssaa)); } if (per_pixel_lighting) { - out.WriteFmt("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++, - GetInterpolationQualifier(msaa, ssaa)); - out.WriteFmt("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++, - GetInterpolationQualifier(msaa, ssaa)); + out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++, + GetInterpolationQualifier(msaa, ssaa)); + out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++, + GetInterpolationQualifier(msaa, ssaa)); } } - out.WriteFmt("void main()\n{{\n"); - out.WriteFmt("\tfloat4 rawpos = gl_FragCoord;\n"); + out.Write("void main()\n{{\n"); + out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); if (use_shader_blend) { // Store off a copy of the initial fb value for blending - out.WriteFmt("\tfloat4 initial_ocol0 = FB_FETCH_VALUE;\n" - "\tfloat4 ocol0;\n" - "\tfloat4 ocol1;\n"); + out.Write("\tfloat4 initial_ocol0 = FB_FETCH_VALUE;\n" + "\tfloat4 ocol0;\n" + "\tfloat4 ocol1;\n"); } } else // D3D { - out.WriteFmt("void main(\n"); + out.Write("void main(\n"); if (uid_data->uint_output) { - out.WriteFmt(" out uint4 ocol0 : SV_Target,\n"); + out.Write(" out uint4 ocol0 : SV_Target,\n"); } else { - out.WriteFmt(" out float4 ocol0 : SV_Target0,\n" - " out float4 ocol1 : SV_Target1,\n"); + out.Write(" out float4 ocol0 : SV_Target0,\n" + " out float4 ocol1 : SV_Target1,\n"); } - out.WriteFmt("{}" - " in float4 rawpos : SV_Position,\n", - uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : ""); + out.Write("{}" + " in float4 rawpos : SV_Position,\n", + uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : ""); - out.WriteFmt(" in {} float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa)); - out.WriteFmt(" in {} float4 colors_1 : COLOR1\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write(" in {} float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write(" in {} float4 colors_1 : COLOR1\n", GetInterpolationQualifier(msaa, ssaa)); // compute window position if needed because binding semantic WPOS is not widely supported for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i) { - out.WriteFmt(",\n in {} float3 tex{} : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), i, - i); + out.Write(",\n in {} float3 tex{} : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), i, + i); } if (!host_config.fast_depth_calc) { - out.WriteFmt(",\n in {} float4 clipPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), - uid_data->genMode_numtexgens); + out.Write(",\n in {} float4 clipPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), + uid_data->genMode_numtexgens); } if (per_pixel_lighting) { - out.WriteFmt(",\n in {} float3 Normal : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), - uid_data->genMode_numtexgens + 1); - out.WriteFmt(",\n in {} float3 WorldPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), - uid_data->genMode_numtexgens + 2); + out.Write(",\n in {} float3 Normal : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), + uid_data->genMode_numtexgens + 1); + out.Write(",\n in {} float3 WorldPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), + uid_data->genMode_numtexgens + 2); } if (host_config.backend_geometry_shaders) { - out.WriteFmt(",\n in float clipDist0 : SV_ClipDistance0\n" - ",\n in float clipDist1 : SV_ClipDistance1\n"); + out.Write(",\n in float clipDist0 : SV_ClipDistance0\n" + ",\n in float clipDist1 : SV_ClipDistance1\n"); } if (stereo) - out.WriteFmt(",\n in uint layer : SV_RenderTargetArrayIndex\n"); - out.WriteFmt(" ) {{\n"); + out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); + out.Write(" ) {{\n"); } - out.WriteFmt( - "\tint4 c0 = " I_COLORS "[1], c1 = " I_COLORS "[2], c2 = " I_COLORS "[3], prev = " I_COLORS - "[0];\n" - "\tint4 rastemp = int4(0, 0, 0, 0), textemp = int4(0, 0, 0, 0), konsttemp = int4(0, 0, " - "0, 0);\n" - "\tint3 comp16 = int3(1, 256, 0), comp24 = int3(1, 256, 256*256);\n" - "\tint alphabump=0;\n" - "\tint3 tevcoord=int3(0, 0, 0);\n" - "\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n" - "\tint4 " - "tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0," - "0);\n\n"); // tev combiner inputs + out.Write("\tint4 c0 = " I_COLORS "[1], c1 = " I_COLORS "[2], c2 = " I_COLORS + "[3], prev = " I_COLORS "[0];\n" + "\tint4 rastemp = int4(0, 0, 0, 0), textemp = int4(0, 0, 0, 0), konsttemp = int4(0, 0, " + "0, 0);\n" + "\tint3 comp16 = int3(1, 256, 0), comp24 = int3(1, 256, 256*256);\n" + "\tint alphabump=0;\n" + "\tint3 tevcoord=int3(0, 0, 0);\n" + "\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n" + "\tint4 " + "tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0," + "0);\n\n"); // tev combiner inputs // On GLSL, input variables must not be assigned to. // This is why we declare these variables locally instead. - out.WriteFmt("\tfloat4 col0 = colors_0;\n" - "\tfloat4 col1 = colors_1;\n"); + out.Write("\tfloat4 col0 = colors_0;\n" + "\tfloat4 col1 = colors_1;\n"); if (per_pixel_lighting) { - out.WriteFmt("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n" - "\tfloat3 pos = WorldPos;\n"); + out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n" + "\tfloat3 pos = WorldPos;\n"); - out.WriteFmt("\tint4 lacc;\n" - "\tfloat3 ldir, h, cosAttn, distAttn;\n" - "\tfloat dist, dist2, attn;\n"); + out.Write("\tint4 lacc;\n" + "\tfloat3 ldir, h, cosAttn, distAttn;\n" + "\tfloat dist, dist2, attn;\n"); // TODO: Our current constant usage code isn't able to handle more than one buffer. // So we can't mark the VS constant as used here. But keep them here as reference. @@ -776,16 +775,16 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // HACK to handle cases where the tex gen is not enabled if (uid_data->genMode_numtexgens == 0) { - out.WriteFmt("\tint2 fixpoint_uv0 = int2(0, 0);\n\n"); + out.Write("\tint2 fixpoint_uv0 = int2(0, 0);\n\n"); } else { out.SetConstantsUsed(C_TEXDIMS, C_TEXDIMS + uid_data->genMode_numtexgens - 1); for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i) { - out.WriteFmt("\tint2 fixpoint_uv{} = int2(", i); - out.WriteFmt("(tex{}.z == 0.0 ? tex{}.xy : tex{}.xy / tex{}.z)", i, i, i, i); - out.WriteFmt(" * " I_TEXDIMS "[{}].zw);\n", i); + out.Write("\tint2 fixpoint_uv{} = int2(", i); + out.Write("(tex{}.z == 0.0 ? tex{}.xy : tex{}.xy / tex{}.z)", i, i, i, i); + out.Write(" * " I_TEXDIMS "[{}].zw);\n", i); // TODO: S24 overflows here? } } @@ -800,15 +799,15 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos if (texcoord < uid_data->genMode_numtexgens) { out.SetConstantsUsed(C_INDTEXSCALE + i / 2, C_INDTEXSCALE + i / 2); - out.WriteFmt("\ttempcoord = fixpoint_uv{} >> " I_INDTEXSCALE "[{}].{};\n", texcoord, i / 2, - (i & 1) != 0 ? "zw" : "xy"); + out.Write("\ttempcoord = fixpoint_uv{} >> " I_INDTEXSCALE "[{}].{};\n", texcoord, i / 2, + (i & 1) != 0 ? "zw" : "xy"); } else { - out.WriteFmt("\ttempcoord = int2(0, 0);\n"); + out.Write("\ttempcoord = int2(0, 0);\n"); } - out.WriteFmt("\tint3 iindtex{} = ", i); + out.Write("\tint3 iindtex{} = ", i); SampleTexture(out, "float2(tempcoord)", "abg", texmap, stereo, api_type); } } @@ -828,14 +827,14 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac; if (last_cc.dest != 0) { - out.WriteFmt("\tprev.rgb = {};\n", tev_c_output_table[last_cc.dest]); + out.Write("\tprev.rgb = {};\n", tev_c_output_table[last_cc.dest]); } if (last_ac.dest != 0) { - out.WriteFmt("\tprev.a = {};\n", tev_a_output_table[last_ac.dest]); + out.Write("\tprev.a = {};\n", tev_a_output_table[last_ac.dest]); } } - out.WriteFmt("\tprev = prev & 255;\n"); + out.Write("\tprev = prev & 255;\n"); // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled // (in this case we need to write a depth value if depth test passes regardless of the alpha @@ -852,14 +851,14 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE); out.SetConstantsUsed(C_EFBSCALE, C_EFBSCALE); - out.WriteFmt("\tfloat2 screenpos = rawpos.xy * " I_EFBSCALE ".xy;\n"); + out.Write("\tfloat2 screenpos = rawpos.xy * " I_EFBSCALE ".xy;\n"); // Opengl has reversed vertical screenspace coordinates if (api_type == APIType::OpenGL) - out.WriteFmt("\tscreenpos.y = {}.0 - screenpos.y;\n", EFB_HEIGHT); + out.Write("\tscreenpos.y = {}.0 - screenpos.y;\n", EFB_HEIGHT); - out.WriteFmt("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE - ".y * screenpos.y);\n"); + out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE + ".y * screenpos.y);\n"); } else if (!host_config.fast_depth_calc) { @@ -870,17 +869,17 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // the host GPU driver from performing any early depth test optimizations. out.SetConstantsUsed(C_ZBIAS + 1, C_ZBIAS + 1); // the screen space depth value = far z + (clip z / clip w) * z range - out.WriteFmt("\tint zCoord = " I_ZBIAS "[1].x + int((clipPos.z / clipPos.w) * float(" I_ZBIAS - "[1].y));\n"); + out.Write("\tint zCoord = " I_ZBIAS "[1].x + int((clipPos.z / clipPos.w) * float(" I_ZBIAS + "[1].y));\n"); } else { if (!host_config.backend_reversed_depth_range) - out.WriteFmt("\tint zCoord = int((1.0 - rawpos.z) * 16777216.0);\n"); + out.Write("\tint zCoord = int((1.0 - rawpos.z) * 16777216.0);\n"); else - out.WriteFmt("\tint zCoord = int(rawpos.z * 16777216.0);\n"); + out.Write("\tint zCoord = int(rawpos.z * 16777216.0);\n"); } - out.WriteFmt("\tzCoord = clamp(zCoord, 0, 0xFFFFFF);\n"); + out.Write("\tzCoord = clamp(zCoord, 0, 0xFFFFFF);\n"); // depth texture can safely be ignored if the result won't be written to the depth buffer // (early_ztest) and isn't used for fog either @@ -890,9 +889,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos if (uid_data->per_pixel_depth && uid_data->early_ztest) { if (!host_config.backend_reversed_depth_range) - out.WriteFmt("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); + out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); else - out.WriteFmt("\tdepth = float(zCoord) / 16777216.0;\n"); + out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); } // Note: depth texture output is only written to depth buffer if late depth test is used @@ -903,17 +902,17 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // use the texture input of the last texture stage (textemp), hopefully this has been read and // is in correct format... out.SetConstantsUsed(C_ZBIAS, C_ZBIAS + 1); - out.WriteFmt("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w {};\n", - (uid_data->ztex_op == ZTEXTURE_ADD) ? "+ zCoord" : ""); - out.WriteFmt("\tzCoord = zCoord & 0xFFFFFF;\n"); + out.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w {};\n", + (uid_data->ztex_op == ZTEXTURE_ADD) ? "+ zCoord" : ""); + out.Write("\tzCoord = zCoord & 0xFFFFFF;\n"); } if (uid_data->per_pixel_depth && uid_data->late_ztest) { if (!host_config.backend_reversed_depth_range) - out.WriteFmt("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); + out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); else - out.WriteFmt("\tdepth = float(zCoord) / 16777216.0;\n"); + out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); } // No dithering for RGB8 mode @@ -921,8 +920,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos { // Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering // Here the matrix is encoded into the two factor constants - out.WriteFmt("\tint2 dither = int2(rawpos.xy) & 1;\n"); - out.WriteFmt("\tprev.rgb = (prev.rgb - (prev.rgb >> 6)) + abs(dither.y * 3 - dither.x * 2);\n"); + out.Write("\tint2 dither = int2(rawpos.xy) & 1;\n"); + out.Write("\tprev.rgb = (prev.rgb - (prev.rgb >> 6)) + abs(dither.y * 3 - dither.x * 2);\n"); } WriteFog(out, uid_data); @@ -935,9 +934,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos WriteBlend(out, uid_data); if (uid_data->bounding_box) - out.WriteFmt("\tUpdateBoundingBox(rawpos.xy);\n"); + out.Write("\tUpdateBoundingBox(rawpos.xy);\n"); - out.WriteFmt("}}\n"); + out.Write("}}\n"); return out; } @@ -946,7 +945,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i APIType api_type, bool stereo) { const auto& stage = uid_data->stagehash[n]; - out.WriteFmt("\n\t// TEV stage {}\n", n); + out.Write("\n\t// TEV stage {}\n", n); // HACK to handle cases where the tex gen is not enabled u32 texcoord = stage.tevorders_texcoord; @@ -959,7 +958,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i TevStageIndirect tevind; tevind.hex = stage.tevind; - out.WriteFmt("\t// indirect op\n"); + out.Write("\t// indirect op\n"); // Perform the indirect op on the incoming regular coordinates // using iindtex{} as the offset coords @@ -980,8 +979,8 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i "248", }; - out.WriteFmt("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(), - tev_ind_alpha_sel[tevind.bs], tev_ind_alpha_mask[tevind.fmt]); + out.Write("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(), tev_ind_alpha_sel[tevind.bs], + tev_ind_alpha_mask[tevind.fmt]); } else { @@ -997,8 +996,8 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i "15", "7", }; - out.WriteFmt("\tint3 iindtevcrd{} = iindtex{} & {};\n", n, tevind.bt.Value(), - tev_ind_fmt_mask[tevind.fmt]); + out.Write("\tint3 iindtevcrd{} = iindtex{} & {};\n", n, tevind.bt.Value(), + tev_ind_fmt_mask[tevind.fmt]); // bias - TODO: Check if this needs to be this complicated... // indexed by bias @@ -1016,19 +1015,19 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i if (tevind.bias == ITB_S || tevind.bias == ITB_T || tevind.bias == ITB_U) { - out.WriteFmt("\tiindtevcrd{}.{} += int({});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{}.{} += int({});\n", n, tev_ind_bias_field[tevind.bias], + tev_ind_bias_add[tevind.fmt]); } else if (tevind.bias == ITB_ST || tevind.bias == ITB_SU || tevind.bias == ITB_TU) { - out.WriteFmt("\tiindtevcrd{}.{} += int2({}, {});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{}.{} += int2({}, {});\n", n, tev_ind_bias_field[tevind.bias], + tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt]); } else if (tevind.bias == ITB_STU) { - out.WriteFmt("\tiindtevcrd{}.{} += int3({}, {}, {});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt], - tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{}.{} += int3({}, {}, {});\n", n, tev_ind_bias_field[tevind.bias], + tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt], + tev_ind_bias_add[tevind.fmt]); } // multiply by offset matrix and scale - calculations are likely to overflow badly, @@ -1038,26 +1037,23 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i const u32 mtxidx = 2 * (tevind.mid - 1); out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.WriteFmt("\tint2 indtevtrans{} = int2(idot(" I_INDTEXMTX - "[{}].xyz, iindtevcrd{}), idot(" I_INDTEXMTX - "[{}].xyz, iindtevcrd{})) >> 3;\n", - n, mtxidx, n, mtxidx + 1, n); + out.Write("\tint2 indtevtrans{} = int2(idot(" I_INDTEXMTX + "[{}].xyz, iindtevcrd{}), idot(" I_INDTEXMTX "[{}].xyz, iindtevcrd{})) >> 3;\n", + n, mtxidx, n, mtxidx + 1, n); // TODO: should use a shader uid branch for this for better performance if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_BITWISE_OP_NEGATION)) { - out.WriteFmt("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= indtexmtx_w_inverse_{};\n", n, n); + out.Write("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= indtexmtx_w_inverse_{};\n", n, n); } else { - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); } } else if (tevind.mid <= 7 && has_tex_coord) @@ -1066,22 +1062,20 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i const u32 mtxidx = 2 * (tevind.mid - 5); out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.WriteFmt("\tint2 indtevtrans{} = int2(fixpoint_uv{} * iindtevcrd{}.xx) >> 8;\n", n, - texcoord, n); + out.Write("\tint2 indtevtrans{} = int2(fixpoint_uv{} * iindtevcrd{}.xx) >> 8;\n", n, + texcoord, n); if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_BITWISE_OP_NEGATION)) { - out.WriteFmt("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= (indtexmtx_w_inverse_{});\n", n, n); + out.Write("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= (indtexmtx_w_inverse_{});\n", n, n); } else { - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); } } else if (tevind.mid <= 11 && has_tex_coord) @@ -1090,33 +1084,31 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i const u32 mtxidx = 2 * (tevind.mid - 9); out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.WriteFmt("\tint2 indtevtrans{} = int2(fixpoint_uv{} * iindtevcrd{}.yy) >> 8;\n", n, - texcoord, n); + out.Write("\tint2 indtevtrans{} = int2(fixpoint_uv{} * iindtevcrd{}.yy) >> 8;\n", n, + texcoord, n); if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_BITWISE_OP_NEGATION)) { - out.WriteFmt("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= (indtexmtx_w_inverse_{});\n", n, n); + out.Write("\tint indtexmtx_w_inverse_{} = -" I_INDTEXMTX "[{}].w;\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= (indtexmtx_w_inverse_{});\n", n, n); } else { - out.WriteFmt("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX - "[{}].w;\n", - mtxidx, n, mtxidx); - out.WriteFmt("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); + out.Write("\tif (" I_INDTEXMTX "[{}].w >= 0) indtevtrans{} >>= " I_INDTEXMTX "[{}].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans{} <<= (-" I_INDTEXMTX "[{}].w);\n", n, mtxidx); } } else { - out.WriteFmt("\tint2 indtevtrans{} = int2(0, 0);\n", n); + out.Write("\tint2 indtevtrans{} = int2(0, 0);\n", n); } } else { - out.WriteFmt("\tint2 indtevtrans{} = int2(0, 0);\n", n); + out.Write("\tint2 indtevtrans{} = int2(0, 0);\n", n); } // --------- @@ -1131,40 +1123,40 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i // wrap S if (tevind.sw == ITW_OFF) { - out.WriteFmt("\twrappedcoord.x = fixpoint_uv{}.x;\n", texcoord); + out.Write("\twrappedcoord.x = fixpoint_uv{}.x;\n", texcoord); } else if (tevind.sw == ITW_0) { - out.WriteFmt("\twrappedcoord.x = 0;\n"); + out.Write("\twrappedcoord.x = 0;\n"); } else { - out.WriteFmt("\twrappedcoord.x = fixpoint_uv{}.x & ({} - 1);\n", texcoord, - tev_ind_wrap_start[tevind.sw]); + out.Write("\twrappedcoord.x = fixpoint_uv{}.x & ({} - 1);\n", texcoord, + tev_ind_wrap_start[tevind.sw]); } // wrap T if (tevind.tw == ITW_OFF) { - out.WriteFmt("\twrappedcoord.y = fixpoint_uv{}.y;\n", texcoord); + out.Write("\twrappedcoord.y = fixpoint_uv{}.y;\n", texcoord); } else if (tevind.tw == ITW_0) { - out.WriteFmt("\twrappedcoord.y = 0;\n"); + out.Write("\twrappedcoord.y = 0;\n"); } else { - out.WriteFmt("\twrappedcoord.y = fixpoint_uv{}.y & ({} - 1);\n", texcoord, - tev_ind_wrap_start[tevind.tw]); + out.Write("\twrappedcoord.y = fixpoint_uv{}.y & ({} - 1);\n", texcoord, + tev_ind_wrap_start[tevind.tw]); } if (tevind.fb_addprev) // add previous tevcoord - out.WriteFmt("\ttevcoord.xy += wrappedcoord + indtevtrans{};\n", n); + out.Write("\ttevcoord.xy += wrappedcoord + indtevtrans{};\n", n); else - out.WriteFmt("\ttevcoord.xy = wrappedcoord + indtevtrans{};\n", n); + out.Write("\ttevcoord.xy = wrappedcoord + indtevtrans{};\n", n); // Emulate s24 overflows - out.WriteFmt("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n"); + out.Write("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n"); } TevStageCombiner::ColorCombiner cc; @@ -1186,7 +1178,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i '\0', }; - out.WriteFmt("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap); + out.Write("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap); } if (stage.tevorders_enable) @@ -1204,24 +1196,24 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i { // calc tevcord if (has_tex_coord) - out.WriteFmt("\ttevcoord.xy = fixpoint_uv{};\n", texcoord); + out.Write("\ttevcoord.xy = fixpoint_uv{};\n", texcoord); else - out.WriteFmt("\ttevcoord.xy = int2(0, 0);\n"); + out.Write("\ttevcoord.xy = int2(0, 0);\n"); } - out.WriteFmt("\ttextemp = "); + out.Write("\ttextemp = "); SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, stereo, api_type); } else { - out.WriteFmt("\ttextemp = int4(255, 255, 255, 255);\n"); + out.Write("\ttextemp = int4(255, 255, 255, 255);\n"); } if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) { - out.WriteFmt("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[stage.tevksel_kc], - tev_ksel_table_a[stage.tevksel_ka]); + out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[stage.tevksel_kc], + tev_ksel_table_a[stage.tevksel_ka]); if (stage.tevksel_kc > 7) { @@ -1250,16 +1242,16 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i if (ac.dest >= GX_TEVREG0) out.SetConstantsUsed(C_COLORS + ac.dest, C_COLORS + ac.dest); - out.WriteFmt("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a], - tev_a_input_table[ac.a]); - out.WriteFmt("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b], - tev_a_input_table[ac.b]); - out.WriteFmt("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c], - tev_a_input_table[ac.c]); - out.WriteFmt("\ttevin_d = int4({}, {});\n", tev_c_input_table[cc.d], tev_a_input_table[ac.d]); + out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a], + tev_a_input_table[ac.a]); + out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b], + tev_a_input_table[ac.b]); + out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c], + tev_a_input_table[ac.c]); + out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[cc.d], tev_a_input_table[ac.d]); - out.WriteFmt("\t// color combine\n"); - out.WriteFmt("\t{} = clamp(", tev_c_output_table[cc.dest]); + out.Write("\t// color combine\n"); + out.Write("\t{} = clamp(", tev_c_output_table[cc.dest]); if (cc.bias != TEVBIAS_COMPARE) { WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.shift, false); @@ -1282,17 +1274,17 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i }; const u32 mode = (cc.shift << 1) | cc.op; - out.WriteFmt(" tevin_d.rgb + "); - out.WriteFmt("{}", function_table[mode]); + out.Write(" tevin_d.rgb + "); + out.Write("{}", function_table[mode]); } if (cc.clamp) - out.WriteFmt(", int3(0,0,0), int3(255,255,255))"); + out.Write(", int3(0,0,0), int3(255,255,255))"); else - out.WriteFmt(", int3(-1024,-1024,-1024), int3(1023,1023,1023))"); - out.WriteFmt(";\n"); + out.Write(", int3(-1024,-1024,-1024), int3(1023,1023,1023))"); + out.Write(";\n"); - out.WriteFmt("\t// alpha combine\n"); - out.WriteFmt("\t{} = clamp(", tev_a_output_table[ac.dest]); + out.Write("\t// alpha combine\n"); + out.Write("\t{} = clamp(", tev_a_output_table[ac.dest]); if (ac.bias != TEVBIAS_COMPARE) { WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.shift, true); @@ -1311,15 +1303,15 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i }; const u32 mode = (ac.shift << 1) | ac.op; - out.WriteFmt(" tevin_d.a + "); - out.WriteFmt("{}", function_table[mode]); + out.Write(" tevin_d.a + "); + out.Write("{}", function_table[mode]); } if (ac.clamp) - out.WriteFmt(", 0, 255)"); + out.Write(", 0, 255)"); else - out.WriteFmt(", -1024, 1023)"); + out.Write(", -1024, 1023)"); - out.WriteFmt(";\n"); + out.Write(";\n"); } static void WriteTevRegular(ShaderCode& out, std::string_view components, int bias, int op, @@ -1364,14 +1356,12 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, int bi // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy // - a rounding bias is added before dividing by 256 - out.WriteFmt("(((tevin_d.{}{}){})", components, tev_bias_table[bias], - tev_scale_table_left[shift]); - out.WriteFmt(" {} ", tev_op_table[op]); - out.WriteFmt( - "(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)", - components, components, components, components, components, tev_scale_table_left[shift], - tev_lerp_bias[2 * op + ((shift == 3) == alpha)]); - out.WriteFmt("){}", tev_scale_table_right[shift]); + out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[shift]); + out.Write(" {} ", tev_op_table[op]); + out.Write("(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)", + components, components, components, components, components, tev_scale_table_left[shift], + tev_lerp_bias[2 * op + ((shift == 3) == alpha)]); + out.Write("){}", tev_scale_table_right[shift]); } static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap, @@ -1381,15 +1371,14 @@ static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::stri if (api_type == APIType::D3D) { - out.WriteFmt("iround(255.0 * Tex[{}].Sample(samp[{}], float3({}.xy * " I_TEXDIMS - "[{}].xy, {}))).{};\n", - texmap, texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap); + out.Write("iround(255.0 * Tex[{}].Sample(samp[{}], float3({}.xy * " I_TEXDIMS + "[{}].xy, {}))).{};\n", + texmap, texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap); } else { - out.WriteFmt("iround(255.0 * texture(samp[{}], float3({}.xy * " I_TEXDIMS - "[{}].xy, {}))).{};\n", - texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap); + out.Write("iround(255.0 * texture(samp[{}], float3({}.xy * " I_TEXDIMS "[{}].xy, {}))).{};\n", + texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap); } } @@ -1422,52 +1411,52 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat const auto write_alpha_func = [&out](int index, std::string_view ref) { const bool has_no_arguments = index == 0 || index == tev_alpha_funcs_table.size() - 1; if (has_no_arguments) - out.WriteFmt("{}", tev_alpha_funcs_table[index]); + out.Write("{}", tev_alpha_funcs_table[index]); else - out.WriteFmt(tev_alpha_funcs_table[index], ref); + out.Write(tev_alpha_funcs_table[index], ref); }; out.SetConstantsUsed(C_ALPHA, C_ALPHA); if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_NEGATED_BOOLEAN)) - out.WriteFmt("\tif(( "); + out.Write("\tif(( "); else - out.WriteFmt("\tif(!( "); + out.Write("\tif(!( "); // Lookup the first component from the alpha function table const int comp0_index = uid_data->alpha_test_comp0; write_alpha_func(comp0_index, alpha_ref[0]); // Lookup the logic op - out.WriteFmt("{}", tev_alpha_funclogic_table[uid_data->alpha_test_logic]); + out.Write("{}", tev_alpha_funclogic_table[uid_data->alpha_test_logic]); // Lookup the second component from the alpha function table const int comp1_index = uid_data->alpha_test_comp1; write_alpha_func(comp1_index, alpha_ref[1]); if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_NEGATED_BOOLEAN)) - out.WriteFmt(") == false) {{\n"); + out.Write(") == false) {{\n"); else - out.WriteFmt(")) {{\n"); + out.Write(")) {{\n"); - out.WriteFmt("\t\tocol0 = float4(0.0, 0.0, 0.0, 0.0);\n"); + out.Write("\t\tocol0 = float4(0.0, 0.0, 0.0, 0.0);\n"); if (use_dual_source && !(api_type == APIType::D3D && uid_data->uint_output)) - out.WriteFmt("\t\tocol1 = float4(0.0, 0.0, 0.0, 0.0);\n"); + out.Write("\t\tocol1 = float4(0.0, 0.0, 0.0, 0.0);\n"); if (per_pixel_depth) { - out.WriteFmt("\t\tdepth = {};\n", - !g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? "0.0" : "1.0"); + out.Write("\t\tdepth = {};\n", + !g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? "0.0" : "1.0"); } // ZCOMPLOC HACK: if (!uid_data->alpha_test_use_zcomploc_hack) { - out.WriteFmt("\t\tdiscard;\n"); + out.Write("\t\tdiscard;\n"); if (api_type == APIType::D3D) - out.WriteFmt("\t\treturn;\n"); + out.Write("\t\treturn;\n"); } - out.WriteFmt("\t}}\n"); + out.Write("\t}}\n"); } constexpr std::array<const char*, 8> tev_fog_funcs_table{ @@ -1497,14 +1486,14 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) // renderer) // Maybe we want to use "ze = (A << B_SHF)/((B << B_SHF) - Zs)" instead? // That's equivalent, but keeps the lower bits of Zs. - out.WriteFmt("\tfloat ze = (" I_FOGF ".x * 16777216.0) / float(" I_FOGI - ".y - (zCoord >> " I_FOGI ".w));\n"); + out.Write("\tfloat ze = (" I_FOGF ".x * 16777216.0) / float(" I_FOGI ".y - (zCoord >> " I_FOGI + ".w));\n"); } else { // orthographic // ze = a*Zs (here, no B_SHF) - out.WriteFmt("\tfloat ze = " I_FOGF ".x * float(zCoord) / 16777216.0;\n"); + out.Write("\tfloat ze = " I_FOGF ".x * float(zCoord) / 16777216.0;\n"); } // x_adjust = sqrt((x-center)^2 + k^2)/k @@ -1512,22 +1501,22 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) if (uid_data->fog_RangeBaseEnabled) { out.SetConstantsUsed(C_FOGF, C_FOGF); - out.WriteFmt("\tfloat offset = (2.0 * (rawpos.x / " I_FOGF ".w)) - 1.0 - " I_FOGF ".z;\n" - "\tfloat floatindex = clamp(9.0 - abs(offset) * 9.0, 0.0, 9.0);\n" - "\tuint indexlower = uint(floatindex);\n" - "\tuint indexupper = indexlower + 1u;\n" - "\tfloat klower = " I_FOGRANGE "[indexlower >> 2u][indexlower & 3u];\n" - "\tfloat kupper = " I_FOGRANGE "[indexupper >> 2u][indexupper & 3u];\n" - "\tfloat k = lerp(klower, kupper, frac(floatindex));\n" - "\tfloat x_adjust = sqrt(offset * offset + k * k) / k;\n" - "\tze *= x_adjust;\n"); + out.Write("\tfloat offset = (2.0 * (rawpos.x / " I_FOGF ".w)) - 1.0 - " I_FOGF ".z;\n" + "\tfloat floatindex = clamp(9.0 - abs(offset) * 9.0, 0.0, 9.0);\n" + "\tuint indexlower = uint(floatindex);\n" + "\tuint indexupper = indexlower + 1u;\n" + "\tfloat klower = " I_FOGRANGE "[indexlower >> 2u][indexlower & 3u];\n" + "\tfloat kupper = " I_FOGRANGE "[indexupper >> 2u][indexupper & 3u];\n" + "\tfloat k = lerp(klower, kupper, frac(floatindex));\n" + "\tfloat x_adjust = sqrt(offset * offset + k * k) / k;\n" + "\tze *= x_adjust;\n"); } - out.WriteFmt("\tfloat fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"); + out.Write("\tfloat fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"); if (uid_data->fog_fsel > 3) { - out.WriteFmt("{}", tev_fog_funcs_table[uid_data->fog_fsel]); + out.Write("{}", tev_fog_funcs_table[uid_data->fog_fsel]); } else { @@ -1535,8 +1524,8 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) WARN_LOG(VIDEO, "Unknown Fog Type! %08x", uid_data->fog_fsel); } - out.WriteFmt("\tint ifog = iround(fog * 256.0);\n"); - out.WriteFmt("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR ".rgb * ifog) >> 8;\n"); + out.Write("\tint ifog = iround(fog * 256.0);\n"); + out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR ".rgb * ifog) >> 8;\n"); } static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid_data* uid_data, @@ -1546,33 +1535,33 @@ static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid if (api_type == APIType::D3D && uid_data->uint_output) { if (uid_data->rgba6_format) - out.WriteFmt("\tocol0 = uint4(prev & 0xFC);\n"); + out.Write("\tocol0 = uint4(prev & 0xFC);\n"); else - out.WriteFmt("\tocol0 = uint4(prev);\n"); + out.Write("\tocol0 = uint4(prev);\n"); return; } if (uid_data->rgba6_format) - out.WriteFmt("\tocol0.rgb = float3(prev.rgb >> 2) / 63.0;\n"); + out.Write("\tocol0.rgb = float3(prev.rgb >> 2) / 63.0;\n"); else - out.WriteFmt("\tocol0.rgb = float3(prev.rgb) / 255.0;\n"); + out.Write("\tocol0.rgb = float3(prev.rgb) / 255.0;\n"); // Colors will be blended against the 8-bit alpha from ocol1 and // the 6-bit alpha from ocol0 will be written to the framebuffer if (uid_data->useDstAlpha) { out.SetConstantsUsed(C_ALPHA, C_ALPHA); - out.WriteFmt("\tocol0.a = float(" I_ALPHA ".a >> 2) / 63.0;\n"); + out.Write("\tocol0.a = float(" I_ALPHA ".a >> 2) / 63.0;\n"); // Use dual-source color blending to perform dst alpha in a single pass if (use_dual_source) - out.WriteFmt("\tocol1 = float4(0.0, 0.0, 0.0, float(prev.a) / 255.0);\n"); + out.Write("\tocol1 = float4(0.0, 0.0, 0.0, float(prev.a) / 255.0);\n"); } else { - out.WriteFmt("\tocol0.a = float(prev.a >> 2) / 63.0;\n"); + out.Write("\tocol0.a = float(prev.a >> 2) / 63.0;\n"); if (use_dual_source) - out.WriteFmt("\tocol1 = float4(0.0, 0.0, 0.0, float(prev.a) / 255.0);\n"); + out.Write("\tocol1 = float4(0.0, 0.0, 0.0, float(prev.a) / 255.0);\n"); } } @@ -1620,34 +1609,34 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data) "initial_ocol0.a;", // DSTALPHA "1.0 - initial_ocol0.a;", // INVDSTALPHA }; - out.WriteFmt("\tfloat4 blend_src;\n"); - out.WriteFmt("\tblend_src.rgb = {}\n", blend_src_factor[uid_data->blend_src_factor]); - out.WriteFmt("\tblend_src.a = {}\n", blend_src_factor_alpha[uid_data->blend_src_factor_alpha]); - out.WriteFmt("\tfloat4 blend_dst;\n"); - out.WriteFmt("\tblend_dst.rgb = {}\n", blend_dst_factor[uid_data->blend_dst_factor]); - out.WriteFmt("\tblend_dst.a = {}\n", blend_dst_factor_alpha[uid_data->blend_dst_factor_alpha]); - - out.WriteFmt("\tfloat4 blend_result;\n"); + out.Write("\tfloat4 blend_src;\n"); + out.Write("\tblend_src.rgb = {}\n", blend_src_factor[uid_data->blend_src_factor]); + out.Write("\tblend_src.a = {}\n", blend_src_factor_alpha[uid_data->blend_src_factor_alpha]); + out.Write("\tfloat4 blend_dst;\n"); + out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[uid_data->blend_dst_factor]); + out.Write("\tblend_dst.a = {}\n", blend_dst_factor_alpha[uid_data->blend_dst_factor_alpha]); + + out.Write("\tfloat4 blend_result;\n"); if (uid_data->blend_subtract) { - out.WriteFmt("\tblend_result.rgb = initial_ocol0.rgb * blend_dst.rgb - ocol0.rgb * " - "blend_src.rgb;\n"); + out.Write("\tblend_result.rgb = initial_ocol0.rgb * blend_dst.rgb - ocol0.rgb * " + "blend_src.rgb;\n"); } else { - out.WriteFmt( + out.Write( "\tblend_result.rgb = initial_ocol0.rgb * blend_dst.rgb + ocol0.rgb * blend_src.rgb;\n"); } if (uid_data->blend_subtract_alpha) - out.WriteFmt("\tblend_result.a = initial_ocol0.a * blend_dst.a - ocol0.a * blend_src.a;\n"); + out.Write("\tblend_result.a = initial_ocol0.a * blend_dst.a - ocol0.a * blend_src.a;\n"); else - out.WriteFmt("\tblend_result.a = initial_ocol0.a * blend_dst.a + ocol0.a * blend_src.a;\n"); + out.Write("\tblend_result.a = initial_ocol0.a * blend_dst.a + ocol0.a * blend_src.a;\n"); } else { - out.WriteFmt("\tfloat4 blend_result = ocol0;\n"); + out.Write("\tfloat4 blend_result = ocol0;\n"); } - out.WriteFmt("\treal_ocol0 = blend_result;\n"); + out.Write("\treal_ocol0 = blend_result;\n"); } |
