summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/PixelShaderGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoCommon/PixelShaderGen.cpp')
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.cpp655
1 files changed, 362 insertions, 293 deletions
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index bc5da9a060..a94cd02c15 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -151,44 +151,209 @@ static const char* tevRasTable[] = {
static const char* tevCOutputTable[] = {"prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb"};
static const char* tevAOutputTable[] = {"prev.a", "c0.a", "c1.a", "c2.a"};
-template <class T>
-static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType,
- const char swapModeTable[4][5]);
-template <class T>
-static void WriteTevRegular(T& out, const char* components, int bias, int op, int clamp, int shift);
-template <class T>
-static void SampleTexture(T& out, const char* texcoords, const char* texswap, int texmap,
- API_TYPE ApiType);
-template <class T>
-static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType,
- DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth);
-template <class T>
-static void WriteFog(T& out, pixel_shader_uid_data* uid_data);
-
-template <class T>
-static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
+// FIXME: Some of the video card's capabilities (BBox support, EarlyZ support, dstAlpha support)
+// leak
+// into this UID; This is really unhelpful if these UIDs ever move from one machine to
+// another.
+PixelShaderUid GetPixelShaderUid(DSTALPHA_MODE dstAlphaMode)
{
- T out;
- const u32 components = VertexLoaderManager::g_current_components;
- // Non-uid template parameters will write to the dummy data (=> gets optimized out)
- pixel_shader_uid_data dummy_data;
- pixel_shader_uid_data* uid_data = out.template GetUidData<pixel_shader_uid_data>();
- if (uid_data != nullptr)
- memset(uid_data, 0, sizeof(*uid_data));
- else
- uid_data = &dummy_data;
-
- unsigned int numStages = bpmem.genMode.numtevstages + 1;
- unsigned int numTexgen = bpmem.genMode.numtexgens;
-
- out.Write("//Pixel Shader for TEV stages\n");
- out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, numTexgen,
- bpmem.genMode.numindstages.Value());
+ PixelShaderUid out;
+ pixel_shader_uid_data* uid_data = out.GetUidData<pixel_shader_uid_data>();
+ memset(uid_data, 0, sizeof(*uid_data));
uid_data->dstAlphaMode = dstAlphaMode;
uid_data->genMode_numindstages = bpmem.genMode.numindstages;
uid_data->genMode_numtevstages = bpmem.genMode.numtevstages;
uid_data->genMode_numtexgens = bpmem.genMode.numtexgens;
+ uid_data->per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
+ uid_data->bounding_box = g_ActiveConfig.backend_info.bSupportsBBox &&
+ g_ActiveConfig.bBBoxEnable && BoundingBox::active;
+
+ u32 numStages = uid_data->genMode_numtevstages + 1;
+
+ const bool forced_early_z =
+ g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() &&
+ (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)
+ // We can't allow early_ztest for zfreeze because depth is overridden per-pixel.
+ // This means it's impossible for zcomploc to be emulated on a zfrozen polygon.
+ && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
+ const bool per_pixel_depth =
+ (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) ||
+ (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) ||
+ (bpmem.zmode.testenable && bpmem.genMode.zfreeze);
+
+ uid_data->per_pixel_depth = per_pixel_depth;
+ uid_data->forced_early_z = forced_early_z;
+ uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc;
+ uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
+ uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
+ uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
+
+ if (!uid_data->forced_early_z && bpmem.UseEarlyDepthTest() &&
+ (!uid_data->fast_depth_calc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
+ {
+ static bool warn_once = true;
+ if (warn_once)
+ WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current "
+ "configuration. Make sure to enable fast depth calculations. If this message "
+ "still shows up your hardware isn't able to emulate the feature properly (a "
+ "GPU with D3D 11.0 / OGL 4.2 support is required).");
+ warn_once = false;
+ }
+
+ if (uid_data->per_pixel_lighting)
+ {
+ // The lighting shader only needs the two color bits of the 23bit component bit array.
+ uid_data->components =
+ (VertexLoaderManager::g_current_components & (VB_HAS_COL0 | VB_HAS_COL1)) >> VB_COL_SHIFT;
+ ;
+ GetLightingShaderUid(uid_data->lighting);
+ }
+
+ if (uid_data->genMode_numtexgens > 0)
+ {
+ for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
+ {
+ // optional perspective divides
+ uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i;
+ }
+ }
+
+ // indirect texture map lookup
+ int nIndirectStagesUsed = 0;
+ if (uid_data->genMode_numindstages > 0)
+ {
+ for (unsigned int i = 0; i < numStages; ++i)
+ {
+ if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < uid_data->genMode_numindstages)
+ nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt;
+ }
+ }
+
+ uid_data->nIndirectStagesUsed = nIndirectStagesUsed;
+ for (u32 i = 0; i < uid_data->genMode_numindstages; ++i)
+ {
+ if (uid_data->nIndirectStagesUsed & (1 << i))
+ uid_data->SetTevindrefValues(i, bpmem.tevindref.getTexCoord(i), bpmem.tevindref.getTexMap(i));
+ }
+
+ for (unsigned int n = 0; n < numStages; n++)
+ {
+ int texcoord = bpmem.tevorders[n / 2].getTexCoord(n & 1);
+ bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens;
+ // HACK to handle cases where the tex gen is not enabled
+ if (!bHasTexCoord)
+ texcoord = bpmem.genMode.numtexgens;
+
+ uid_data->stagehash[n].hasindstage = bpmem.tevind[n].bt < bpmem.genMode.numindstages;
+ uid_data->stagehash[n].tevorders_texcoord = texcoord;
+ if (uid_data->stagehash[n].hasindstage)
+ uid_data->stagehash[n].tevind = bpmem.tevind[n].hex;
+
+ TevStageCombiner::ColorCombiner& cc = bpmem.combiners[n].colorC;
+ TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[n].alphaC;
+ uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF;
+ uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later
+
+ if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA ||
+ cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC ||
+ cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA ||
+ ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA)
+ {
+ const int i = bpmem.combiners[n].alphaC.rswap;
+ uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1;
+ uid_data->stagehash[n].tevksel_swap2a = bpmem.tevksel[i * 2].swap2;
+ uid_data->stagehash[n].tevksel_swap1b = bpmem.tevksel[i * 2 + 1].swap1;
+ uid_data->stagehash[n].tevksel_swap2b = bpmem.tevksel[i * 2 + 1].swap2;
+ uid_data->stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1);
+ }
+
+ uid_data->stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1);
+ if (uid_data->stagehash[n].tevorders_enable)
+ {
+ const int i = bpmem.combiners[n].alphaC.tswap;
+ uid_data->stagehash[n].tevksel_swap1c = bpmem.tevksel[i * 2].swap1;
+ uid_data->stagehash[n].tevksel_swap2c = bpmem.tevksel[i * 2].swap2;
+ uid_data->stagehash[n].tevksel_swap1d = bpmem.tevksel[i * 2 + 1].swap1;
+ uid_data->stagehash[n].tevksel_swap2d = bpmem.tevksel[i * 2 + 1].swap2;
+ uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1);
+ }
+
+ 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)
+ {
+ uid_data->stagehash[n].tevksel_kc = bpmem.tevksel[n / 2].getKC(n & 1);
+ uid_data->stagehash[n].tevksel_ka = bpmem.tevksel[n / 2].getKA(n & 1);
+ }
+ }
+
+#define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
+ uid_data->num_values = (uid_data->per_pixel_lighting) ?
+ sizeof(*uid_data) :
+ MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]);
+
+ AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult();
+ uid_data->Pretest = Pretest;
+ uid_data->late_ztest = bpmem.UseLateDepthTest();
+
+ // 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
+ // testing result)
+ if (uid_data->Pretest == AlphaTest::UNDETERMINED ||
+ (uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest))
+ {
+ uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0;
+ uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1;
+ uid_data->alpha_test_logic = bpmem.alpha_test.logic;
+
+ // ZCOMPLOC HACK:
+ // The only way to emulate alpha test + early-z is to force early-z in the shader.
+ // As this isn't available on all drivers and as we can't emulate this feature otherwise,
+ // we are only able to choose which one we want to respect more.
+ // Tests seem to have proven that writing depth even when the alpha test fails is more
+ // important that a reliable alpha test, so we just force the alpha test to always succeed.
+ // At least this seems to be less buggy.
+ uid_data->alpha_test_use_zcomploc_hack =
+ bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable &&
+ !g_ActiveConfig.backend_info.bSupportsEarlyZ && !bpmem.genMode.zfreeze;
+ }
+
+ uid_data->zfreeze = bpmem.genMode.zfreeze;
+ uid_data->ztex_op = bpmem.ztex2.op;
+ uid_data->early_ztest = bpmem.UseEarlyDepthTest();
+ uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
+
+ if (dstAlphaMode != DSTALPHA_ALPHA_PASS)
+ {
+ uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
+ uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj;
+ uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled;
+ }
+
+ return out;
+}
+
+static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
+ API_TYPE ApiType);
+static void WriteTevRegular(ShaderCode& out, const char* components, int bias, int op, int clamp,
+ int shift);
+static void SampleTexture(ShaderCode& out, const char* texcoords, const char* texswap, int texmap,
+ bool stereo, API_TYPE ApiType);
+static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, API_TYPE ApiType,
+ DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth);
+static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data);
+
+ShaderCode GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType,
+ const pixel_shader_uid_data* uid_data)
+{
+ ShaderCode out;
+
+ u32 numStages = uid_data->genMode_numtevstages + 1;
+
+ out.Write("//Pixel Shader for TEV stages\n");
+ out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, uid_data->genMode_numtexgens,
+ uid_data->genMode_numindstages);
// dot product for integer vectors
out.Write("int idot(int3 x, int3 y)\n"
@@ -250,7 +415,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
"\tfloat4 " I_EFBSCALE ";\n"
"};\n");
- if (g_ActiveConfig.bEnablePixelLighting)
+ if (uid_data->per_pixel_lighting)
{
out.Write("%s", s_lighting_struct);
@@ -267,7 +432,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write("};\n");
}
- if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable)
+ if (uid_data->bounding_box)
{
if (ApiType == API_OPENGL)
{
@@ -282,21 +447,11 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
}
out.Write("struct VS_OUTPUT {\n");
- GenerateVSOutputMembers<T>(out, ApiType, "");
+ GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting,
+ "");
out.Write("};\n");
- const bool forced_early_z =
- g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() &&
- (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)
- // We can't allow early_ztest for zfreeze because depth is overridden per-pixel.
- // This means it's impossible for zcomploc to be emulated on a zfrozen polygon.
- && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
- const bool per_pixel_depth =
- (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) ||
- (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) ||
- (bpmem.zmode.testenable && bpmem.genMode.zfreeze);
-
- if (forced_early_z)
+ if (uid_data->forced_early_z)
{
// Zcomploc (aka early_ztest) is a way to control whether depth test is done before
// or after texturing and alpha test. PC graphics APIs used to provide no way to emulate
@@ -319,7 +474,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
// can be made and
// doesn't define what will happen if we discard the fragment. But the way modern graphics
// hardware is implemented
- // means it is not unreasonable to expect the the same behaviour as early_fragment_tests.
+ // means it is not unreasonable to expect the same behaviour as early_fragment_tests.
// We can also assume that if a driver has gone out of its way to support conservative depth and
// not image_load_store
// as required by OpenGL 4.2 that it will be doing the optimisation.
@@ -342,8 +497,8 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write("[earlydepthstencil]\n");
}
}
- else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc ||
- bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
+ else if (bpmem.UseEarlyDepthTest() &&
+ (uid_data->fast_depth_calc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
{
static bool warn_once = true;
if (warn_once)
@@ -354,43 +509,48 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
warn_once = false;
}
- uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
- uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
if (ApiType == API_OPENGL)
{
out.Write("out vec4 ocol0;\n");
if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND)
out.Write("out vec4 ocol1;\n");
- if (per_pixel_depth)
+ if (uid_data->per_pixel_depth)
out.Write("#define depth gl_FragDepth\n");
- uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
out.Write("in VertexData {\n");
- GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(true, true));
+ GenerateVSOutputMembers(
+ out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting,
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true));
- if (g_ActiveConfig.iStereoMode > 0)
+ if (uid_data->stereo)
out.Write("\tflat int layer;\n");
out.Write("};\n");
}
else
{
- out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier());
- out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier());
+ out.Write("%s in float4 colors_0;\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
+ out.Write("%s in float4 colors_1;\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
- for (unsigned int i = 0; i < numTexgen; ++i)
+ for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
{
- out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(), i);
+ out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
+ i);
}
- out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier());
- if (g_ActiveConfig.bEnablePixelLighting)
+ out.Write("%s in float4 clipPos;\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
+ if (uid_data->per_pixel_lighting)
{
- out.Write("%s in float3 Normal;\n", GetInterpolationQualifier());
- out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier());
+ out.Write("%s in float3 Normal;\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
+ out.Write("%s in float3 WorldPos;\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
}
}
@@ -398,7 +558,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
- for (unsigned int i = 0; i < numTexgen; ++i)
+ for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
out.Write("\tfloat3 uv%d = tex%d;\n", i, i);
}
@@ -410,24 +570,30 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write(" out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n",
dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," :
"",
- per_pixel_depth ? "\n out float depth : SV_Depth," : "");
+ uid_data->per_pixel_depth ? "\n out float depth : SV_Depth," : "");
- out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier());
- out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier());
+ out.Write(" in %s float4 colors_0 : COLOR0,\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
+ out.Write(" in %s float4 colors_1 : COLOR1\n",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa));
// compute window position if needed because binding semantic WPOS is not widely supported
- for (unsigned int i = 0; i < numTexgen; ++i)
- out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(), i, i);
- out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen);
- if (g_ActiveConfig.bEnablePixelLighting)
+ for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
+ out.Write(",\n in %s float3 uv%d : TEXCOORD%d",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i, i);
+ out.Write(",\n in %s float4 clipPos : TEXCOORD%d",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
+ uid_data->genMode_numtexgens);
+ if (uid_data->per_pixel_lighting)
{
- out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(),
- numTexgen + 1);
- out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(),
- numTexgen + 2);
+ out.Write(",\n in %s float3 Normal : TEXCOORD%d",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
+ uid_data->genMode_numtexgens + 1);
+ out.Write(",\n in %s float3 WorldPos : TEXCOORD%d",
+ GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
+ uid_data->genMode_numtexgens + 2);
}
- uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
- if (g_ActiveConfig.iStereoMode > 0)
+ if (uid_data->stereo)
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
out.Write(" ) {\n");
}
@@ -449,7 +615,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write("\tfloat4 col0 = colors_0;\n");
out.Write("\tfloat4 col1 = colors_1;\n");
- if (g_ActiveConfig.bEnablePixelLighting)
+ if (uid_data->per_pixel_lighting)
{
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
out.Write("\tfloat3 pos = WorldPos;\n");
@@ -463,24 +629,23 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
// out.SetConstantsUsed(C_PLIGHT_COLORS, C_PLIGHT_COLORS+7); // TODO: Can be optimized further
// out.SetConstantsUsed(C_PLIGHTS, C_PLIGHTS+31); // TODO: Can be optimized further
// out.SetConstantsUsed(C_PMATERIALS, C_PMATERIALS+3);
- uid_data->components = components;
- GenerateLightingShader<T>(out, uid_data->lighting, components, "colors_", "col");
+ GenerateLightingShaderCode(out, uid_data->lighting, uid_data->components << VB_COL_SHIFT,
+ "colors_", "col");
}
// HACK to handle cases where the tex gen is not enabled
- if (numTexgen == 0)
+ if (uid_data->genMode_numtexgens == 0)
{
out.Write("\tint2 fixpoint_uv0 = int2(0, 0);\n\n");
}
else
{
- out.SetConstantsUsed(C_TEXDIMS, C_TEXDIMS + numTexgen - 1);
- for (unsigned int i = 0; i < numTexgen; ++i)
+ out.SetConstantsUsed(C_TEXDIMS, C_TEXDIMS + uid_data->genMode_numtexgens - 1);
+ for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i)
{
out.Write("\tint2 fixpoint_uv%d = itrunc(", i);
// optional perspective divides
- uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i;
- if (xfmem.texMtxInfo[i].projection == XF_TEXPROJ_STQ)
+ if (((uid_data->texMtxInfo_n_projection >> i) & 1) == XF_TEXPROJ_STQ)
{
out.Write("(uv%d.z == 0.0 ? uv%d.xy : uv%d.xy / uv%d.z)", i, i, i, i);
}
@@ -493,27 +658,14 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
}
}
- // indirect texture map lookup
- int nIndirectStagesUsed = 0;
- if (bpmem.genMode.numindstages > 0)
+ for (u32 i = 0; i < uid_data->genMode_numindstages; ++i)
{
- for (unsigned int i = 0; i < numStages; ++i)
+ if (uid_data->nIndirectStagesUsed & (1 << i))
{
- if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
- nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt;
- }
- }
+ unsigned int texcoord = uid_data->GetTevindirefCoord(i);
+ unsigned int texmap = uid_data->GetTevindirefMap(i);
- uid_data->nIndirectStagesUsed = nIndirectStagesUsed;
- for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
- {
- if (nIndirectStagesUsed & (1 << i))
- {
- unsigned int texcoord = bpmem.tevindref.getTexCoord(i);
- unsigned int texmap = bpmem.tevindref.getTexMap(i);
-
- uid_data->SetTevindrefValues(i, texcoord, texmap);
- if (texcoord < numTexgen)
+ if (texcoord < uid_data->genMode_numtexgens)
{
out.SetConstantsUsed(C_INDTEXSCALE + i / 2, C_INDTEXSCALE + i / 2);
out.Write("\ttempcoord = fixpoint_uv%d >> " I_INDTEXSCALE "[%d].%s;\n", texcoord, i / 2,
@@ -523,70 +675,53 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write("\ttempcoord = int2(0, 0);\n");
out.Write("\tint3 iindtex%d = ", i);
- SampleTexture<T>(out, "float2(tempcoord)", "abg", texmap, ApiType);
+ SampleTexture(out, "float2(tempcoord)", "abg", texmap, uid_data->stereo, ApiType);
}
}
- // Uid fields for BuildSwapModeTable are set in WriteStage
- char swapModeTable[4][5];
- const char* swapColors = "rgba";
- for (int i = 0; i < 4; i++)
- {
- swapModeTable[i][0] = swapColors[bpmem.tevksel[i * 2].swap1];
- swapModeTable[i][1] = swapColors[bpmem.tevksel[i * 2].swap2];
- swapModeTable[i][2] = swapColors[bpmem.tevksel[i * 2 + 1].swap1];
- swapModeTable[i][3] = swapColors[bpmem.tevksel[i * 2 + 1].swap2];
- swapModeTable[i][4] = '\0';
- }
-
for (unsigned int i = 0; i < numStages; i++)
- WriteStage<T>(out, uid_data, i, ApiType, swapModeTable); // build the equation for this stage
+ WriteStage(out, uid_data, i, ApiType); // build the equation for this stage
-#define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
- bool enable_pl = g_ActiveConfig.bEnablePixelLighting;
- uid_data->num_values =
- (enable_pl) ? sizeof(*uid_data) : MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]);
-
- if (numStages)
{
// The results of the last texenv stage are put onto the screen,
// regardless of the used destination register
- if (bpmem.combiners[numStages - 1].colorC.dest != 0)
+ TevStageCombiner::ColorCombiner last_cc;
+ TevStageCombiner::AlphaCombiner last_ac;
+ last_cc.hex = uid_data->stagehash[uid_data->genMode_numtevstages].cc;
+ last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac;
+ if (last_cc.dest != 0)
{
- out.Write("\tprev.rgb = %s;\n", tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]);
+ out.Write("\tprev.rgb = %s;\n", tevCOutputTable[last_cc.dest]);
}
- if (bpmem.combiners[numStages - 1].alphaC.dest != 0)
+ if (last_ac.dest != 0)
{
- out.Write("\tprev.a = %s;\n", tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]);
+ out.Write("\tprev.a = %s;\n", tevAOutputTable[last_ac.dest]);
}
}
out.Write("\tprev = prev & 255;\n");
- AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult();
- uid_data->Pretest = Pretest;
-
// 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
// testing result)
- if (Pretest == AlphaTest::UNDETERMINED ||
- (Pretest == AlphaTest::FAIL && bpmem.UseLateDepthTest()))
- WriteAlphaTest<T>(out, uid_data, ApiType, dstAlphaMode, per_pixel_depth);
+ if (uid_data->Pretest == AlphaTest::UNDETERMINED ||
+ (uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest))
+ WriteAlphaTest(out, uid_data, ApiType, dstAlphaMode, uid_data->per_pixel_depth);
- if (bpmem.genMode.zfreeze)
+ if (uid_data->zfreeze)
{
out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE);
out.SetConstantsUsed(C_EFBSCALE, C_EFBSCALE);
out.Write("\tfloat2 screenpos = rawpos.xy * " I_EFBSCALE ".xy;\n");
- // Opengl has reversed vertical screenspace coordiantes
+ // Opengl has reversed vertical screenspace coordinates
if (ApiType == API_OPENGL)
out.Write("\tscreenpos.y = %i.0 - screenpos.y;\n", EFB_HEIGHT);
out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE
".y * screenpos.y);\n");
}
- else if (!g_ActiveConfig.bFastDepthCalc)
+ else if (!uid_data->fast_depth_calc)
{
// FastDepth means to trust the depth generated in perspective division.
// It should be correct, but it seems not to be as accurate as required. TODO: Find out why!
@@ -609,18 +744,10 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
// 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
- const bool skip_ztexture = !per_pixel_depth && !bpmem.fog.c_proj_fsel.fsel;
-
- uid_data->ztex_op = bpmem.ztex2.op;
- uid_data->per_pixel_depth = per_pixel_depth;
- uid_data->forced_early_z = forced_early_z;
- uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc;
- uid_data->early_ztest = bpmem.UseEarlyDepthTest();
- uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
- uid_data->zfreeze = bpmem.genMode.zfreeze;
+ const bool skip_ztexture = !uid_data->per_pixel_depth && !uid_data->fog_fsel;
// Note: z-textures are not written to depth buffer if early depth test is used
- if (per_pixel_depth && bpmem.UseEarlyDepthTest())
+ if (uid_data->per_pixel_depth && uid_data->early_ztest)
{
if (ApiType == API_D3D)
out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n");
@@ -631,17 +758,17 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
// Note: depth texture output is only written to depth buffer if late depth test is used
// theoretical final depth value is used for fog calculation, though, so we have to emulate
// ztextures anyway
- if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !skip_ztexture)
+ if (uid_data->ztex_op != ZTEXTURE_DISABLE && !skip_ztexture)
{
// 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.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w %s;\n",
- (bpmem.ztex2.op == ZTEXTURE_ADD) ? "+ zCoord" : "");
+ (uid_data->ztex_op == ZTEXTURE_ADD) ? "+ zCoord" : "");
out.Write("\tzCoord = zCoord & 0xFFFFFF;\n");
}
- if (per_pixel_depth && bpmem.UseLateDepthTest())
+ if (uid_data->per_pixel_depth && uid_data->late_ztest)
{
if (ApiType == API_D3D)
out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n");
@@ -656,7 +783,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
}
else
{
- WriteFog<T>(out, uid_data);
+ WriteFog(out, uid_data);
out.Write("\tocol0 = float4(prev) / 255.0;\n");
}
@@ -671,10 +798,8 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
out.Write("\tocol0.a = float(" I_ALPHA ".a) / 255.0;\n");
}
- if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable &&
- BoundingBox::active)
+ if (uid_data->bounding_box)
{
- uid_data->bounding_box = true;
const char* atomic_op = ApiType == API_OPENGL ? "atomic" : "Interlocked";
out.Write("\tif(bbox_data[0] > int(rawpos.x)) %sMin(bbox_data[0], int(rawpos.x));\n"
"\tif(bbox_data[1] < int(rawpos.x)) %sMax(bbox_data[1], int(rawpos.x));\n"
@@ -688,70 +813,64 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
return out;
}
-template <class T>
-static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType,
- const char swapModeTable[4][5])
+static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
+ API_TYPE ApiType)
{
- int texcoord = bpmem.tevorders[n / 2].getTexCoord(n & 1);
- bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens;
- bool bHasIndStage = bpmem.tevind[n].bt < bpmem.genMode.numindstages;
+ auto& stage = uid_data->stagehash[n];
+ out.Write("\n\t// TEV stage %d\n", n);
+
// HACK to handle cases where the tex gen is not enabled
+ u32 texcoord = stage.tevorders_texcoord;
+ bool bHasTexCoord = texcoord < uid_data->genMode_numtexgens;
if (!bHasTexCoord)
texcoord = 0;
- out.Write("\n\t// TEV stage %d\n", n);
-
- uid_data->stagehash[n].hasindstage = bHasIndStage;
- uid_data->stagehash[n].tevorders_texcoord = texcoord;
- if (bHasIndStage)
+ if (stage.hasindstage)
{
- uid_data->stagehash[n].tevind = bpmem.tevind[n].hex & 0x7FFFFF;
+ TevStageIndirect tevind;
+ tevind.hex = stage.tevind;
out.Write("\t// indirect op\n");
// perform the indirect op on the incoming regular coordinates using iindtex%d as the offset
// coords
- if (bpmem.tevind[n].bs != ITBA_OFF)
+ if (tevind.bs != ITBA_OFF)
{
const char* tevIndAlphaSel[] = {"", "x", "y", "z"};
const char* tevIndAlphaMask[] = {"248", "224", "240",
"248"}; // 0b11111000, 0b11100000, 0b11110000, 0b11111000
- out.Write("alphabump = iindtex%d.%s & %s;\n", bpmem.tevind[n].bt,
- tevIndAlphaSel[bpmem.tevind[n].bs], tevIndAlphaMask[bpmem.tevind[n].fmt]);
+ out.Write("alphabump = iindtex%d.%s & %s;\n", tevind.bt, tevIndAlphaSel[tevind.bs],
+ tevIndAlphaMask[tevind.fmt]);
}
else
{
// TODO: Should we reset alphabump to 0 here?
}
- if (bpmem.tevind[n].mid != 0)
+ if (tevind.mid != 0)
{
// format
const char* tevIndFmtMask[] = {"255", "31", "15", "7"};
- out.Write("\tint3 iindtevcrd%d = iindtex%d & %s;\n", n, bpmem.tevind[n].bt,
- tevIndFmtMask[bpmem.tevind[n].fmt]);
+ out.Write("\tint3 iindtevcrd%d = iindtex%d & %s;\n", n, tevind.bt, tevIndFmtMask[tevind.fmt]);
// bias - TODO: Check if this needs to be this complicated..
const char* tevIndBiasField[] = {"", "x", "y", "xy",
"z", "xz", "yz", "xyz"}; // indexed by bias
const char* tevIndBiasAdd[] = {"-128", "1", "1", "1"}; // indexed by fmt
- if (bpmem.tevind[n].bias == ITB_S || bpmem.tevind[n].bias == ITB_T ||
- bpmem.tevind[n].bias == ITB_U)
- out.Write("\tiindtevcrd%d.%s += int(%s);\n", n, tevIndBiasField[bpmem.tevind[n].bias],
- tevIndBiasAdd[bpmem.tevind[n].fmt]);
- else if (bpmem.tevind[n].bias == ITB_ST || bpmem.tevind[n].bias == ITB_SU ||
- bpmem.tevind[n].bias == ITB_TU)
- out.Write("\tiindtevcrd%d.%s += int2(%s, %s);\n", n, tevIndBiasField[bpmem.tevind[n].bias],
- tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]);
- else if (bpmem.tevind[n].bias == ITB_STU)
- out.Write("\tiindtevcrd%d.%s += int3(%s, %s, %s);\n", n,
- tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt],
- tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]);
+ if (tevind.bias == ITB_S || tevind.bias == ITB_T || tevind.bias == ITB_U)
+ out.Write("\tiindtevcrd%d.%s += int(%s);\n", n, tevIndBiasField[tevind.bias],
+ tevIndBiasAdd[tevind.fmt]);
+ else if (tevind.bias == ITB_ST || tevind.bias == ITB_SU || tevind.bias == ITB_TU)
+ out.Write("\tiindtevcrd%d.%s += int2(%s, %s);\n", n, tevIndBiasField[tevind.bias],
+ tevIndBiasAdd[tevind.fmt], tevIndBiasAdd[tevind.fmt]);
+ else if (tevind.bias == ITB_STU)
+ out.Write("\tiindtevcrd%d.%s += int3(%s, %s, %s);\n", n, tevIndBiasField[tevind.bias],
+ tevIndBiasAdd[tevind.fmt], tevIndBiasAdd[tevind.fmt], tevIndBiasAdd[tevind.fmt]);
// multiply by offset matrix and scale - calculations are likely to overflow badly,
// yet it works out since we only care about the lower 23 bits (+1 sign bit) of the result
- if (bpmem.tevind[n].mid <= 3)
+ if (tevind.mid <= 3)
{
- int mtxidx = 2 * (bpmem.tevind[n].mid - 1);
+ int mtxidx = 2 * (tevind.mid - 1);
out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx);
out.Write("\tint2 indtevtrans%d = int2(idot(" I_INDTEXMTX
@@ -763,10 +882,10 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
mtxidx, n, mtxidx);
out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX "[%d].w);\n", n, mtxidx);
}
- else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord)
+ else if (tevind.mid <= 7 && bHasTexCoord)
{ // s matrix
- _assert_(bpmem.tevind[n].mid >= 5);
- int mtxidx = 2 * (bpmem.tevind[n].mid - 5);
+ _assert_(tevind.mid >= 5);
+ int mtxidx = 2 * (tevind.mid - 5);
out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx);
out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.xx) >> 8;\n", n,
@@ -776,10 +895,10 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
mtxidx, n, mtxidx);
out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX "[%d].w);\n", n, mtxidx);
}
- else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord)
+ else if (tevind.mid <= 11 && bHasTexCoord)
{ // t matrix
- _assert_(bpmem.tevind[n].mid >= 9);
- int mtxidx = 2 * (bpmem.tevind[n].mid - 9);
+ _assert_(tevind.mid >= 9);
+ int mtxidx = 2 * (tevind.mid - 9);
out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx);
out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.yy) >> 8;\n", n,
@@ -807,24 +926,24 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
"(32<<7)", "(16<<7)", "1"}; // TODO: Should the last one be 1 or (1<<7)?
// wrap S
- if (bpmem.tevind[n].sw == ITW_OFF)
+ if (tevind.sw == ITW_OFF)
out.Write("\twrappedcoord.x = fixpoint_uv%d.x;\n", texcoord);
- else if (bpmem.tevind[n].sw == ITW_0)
+ else if (tevind.sw == ITW_0)
out.Write("\twrappedcoord.x = 0;\n");
else
out.Write("\twrappedcoord.x = fixpoint_uv%d.x & (%s - 1);\n", texcoord,
- tevIndWrapStart[bpmem.tevind[n].sw]);
+ tevIndWrapStart[tevind.sw]);
// wrap T
- if (bpmem.tevind[n].tw == ITW_OFF)
+ if (tevind.tw == ITW_OFF)
out.Write("\twrappedcoord.y = fixpoint_uv%d.y;\n", texcoord);
- else if (bpmem.tevind[n].tw == ITW_0)
+ else if (tevind.tw == ITW_0)
out.Write("\twrappedcoord.y = 0;\n");
else
out.Write("\twrappedcoord.y = fixpoint_uv%d.y & (%s - 1);\n", texcoord,
- tevIndWrapStart[bpmem.tevind[n].tw]);
+ tevIndWrapStart[tevind.tw]);
- if (bpmem.tevind[n].fb_addprev) // add previous tevcoord
+ if (tevind.fb_addprev) // add previous tevcoord
out.Write("\ttevcoord.xy += wrappedcoord + indtevtrans%d;\n", n);
else
out.Write("\ttevcoord.xy = wrappedcoord + indtevtrans%d;\n", n);
@@ -833,35 +952,30 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
out.Write("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n");
}
- TevStageCombiner::ColorCombiner& cc = bpmem.combiners[n].colorC;
- TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[n].alphaC;
-
- uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF;
- uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later
+ TevStageCombiner::ColorCombiner cc;
+ TevStageCombiner::AlphaCombiner ac;
+ cc.hex = stage.cc;
+ ac.hex = stage.ac;
if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA ||
cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC ||
cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA ||
ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA)
{
- const int i = bpmem.combiners[n].alphaC.rswap;
- uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.rswap;
- uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1;
- uid_data->stagehash[n].tevksel_swap2a = bpmem.tevksel[i * 2].swap2;
- uid_data->stagehash[n].tevksel_swap1b = bpmem.tevksel[i * 2 + 1].swap1;
- uid_data->stagehash[n].tevksel_swap2b = bpmem.tevksel[i * 2 + 1].swap2;
- uid_data->stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1);
-
- const char* rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap];
- out.Write("\trastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)],
- rasswap);
+ // Generate swizzle string to represent the Ras color channel swapping
+ char rasswap[5] = {"rgba"[stage.tevksel_swap1a], "rgba"[stage.tevksel_swap2a],
+ "rgba"[stage.tevksel_swap1b], "rgba"[stage.tevksel_swap2b], '\0'};
+
+ out.Write("\trastemp = %s.%s;\n", tevRasTable[stage.tevorders_colorchan], rasswap);
}
- uid_data->stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1);
- if (bpmem.tevorders[n / 2].getEnable(n & 1))
+ if (stage.tevorders_enable)
{
- int texmap = bpmem.tevorders[n / 2].getTexMap(n & 1);
- if (!bHasIndStage)
+ // Generate swizzle string to represent the texture color channel swapping
+ char texswap[5] = {"rgba"[stage.tevksel_swap1c], "rgba"[stage.tevksel_swap2c],
+ "rgba"[stage.tevksel_swap1d], "rgba"[stage.tevksel_swap2d], '\0'};
+
+ if (!stage.hasindstage)
{
// calc tevcord
if (bHasTexCoord)
@@ -869,21 +983,9 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
else
out.Write("\ttevcoord.xy = int2(0, 0);\n");
}
-
- const int i = bpmem.combiners[n].alphaC.tswap;
- uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.tswap << 2;
- uid_data->stagehash[n].tevksel_swap1c = bpmem.tevksel[i * 2].swap1;
- uid_data->stagehash[n].tevksel_swap2c = bpmem.tevksel[i * 2].swap2;
- uid_data->stagehash[n].tevksel_swap1d = bpmem.tevksel[i * 2 + 1].swap1;
- uid_data->stagehash[n].tevksel_swap2d = bpmem.tevksel[i * 2 + 1].swap2;
-
- uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1);
-
- const char* texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap];
- uid_data->SetTevindrefTexmap(i, texmap);
-
out.Write("\ttextemp = ");
- SampleTexture<T>(out, "float2(tevcoord.xy)", texswap, texmap, ApiType);
+ SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, uid_data->stereo,
+ ApiType);
}
else
{
@@ -894,16 +996,15 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST ||
ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST)
{
- int kc = bpmem.tevksel[n / 2].getKC(n & 1);
- int ka = bpmem.tevksel[n / 2].getKA(n & 1);
- uid_data->stagehash[n].tevksel_kc = kc;
- uid_data->stagehash[n].tevksel_ka = ka;
- out.Write("\tkonsttemp = int4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]);
-
- if (kc > 7)
- out.SetConstantsUsed(C_KCOLORS + ((kc - 0xc) % 4), C_KCOLORS + ((kc - 0xc) % 4));
- if (ka > 7)
- out.SetConstantsUsed(C_KCOLORS + ((ka - 0xc) % 4), C_KCOLORS + ((ka - 0xc) % 4));
+ out.Write("\tkonsttemp = int4(%s, %s);\n", tevKSelTableC[stage.tevksel_kc],
+ tevKSelTableA[stage.tevksel_ka]);
+
+ if (stage.tevksel_kc > 7)
+ out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4),
+ C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4));
+ if (stage.tevksel_ka > 7)
+ out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4),
+ C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4));
}
if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0)
@@ -993,8 +1094,8 @@ static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE
out.Write(";\n");
}
-template <class T>
-static void WriteTevRegular(T& out, const char* components, int bias, int op, int clamp, int shift)
+static void WriteTevRegular(ShaderCode& out, const char* components, int bias, int op, int clamp,
+ int shift)
{
const char* tevScaleTableLeft[] = {
"", // SCALE_1
@@ -1040,20 +1141,18 @@ static void WriteTevRegular(T& out, const char* components, int bias, int op, in
out.Write(")%s", tevScaleTableRight[shift]);
}
-template <class T>
-static void SampleTexture(T& out, const char* texcoords, const char* texswap, int texmap,
- API_TYPE ApiType)
+static void SampleTexture(ShaderCode& out, const char* texcoords, const char* texswap, int texmap,
+ bool stereo, API_TYPE ApiType)
{
out.SetConstantsUsed(C_TEXDIMS + texmap, C_TEXDIMS + texmap);
if (ApiType == API_D3D)
out.Write("iround(255.0 * Tex[%d].Sample(samp[%d], float3(%s.xy * " I_TEXDIMS
"[%d].xy, %s))).%s;\n",
- texmap, texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0",
- texswap);
+ texmap, texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap);
else
out.Write("iround(255.0 * texture(samp[%d], float3(%s.xy * " I_TEXDIMS "[%d].xy, %s))).%s;\n",
- texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap);
+ texmap, texcoords, texmap, stereo ? "layer" : "0.0", texswap);
}
static const char* tevAlphaFuncsTable[] = {
@@ -1074,8 +1173,7 @@ static const char* tevAlphaFunclogicTable[] = {
" == " // xnor
};
-template <class T>
-static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType,
+static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, API_TYPE ApiType,
DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth)
{
static const char* alphaRef[2] = {I_ALPHA ".r", I_ALPHA ".g"};
@@ -1087,18 +1185,14 @@ static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE Api
else
out.Write("\tif(!( ");
- uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0;
- uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1;
- uid_data->alpha_test_logic = bpmem.alpha_test.logic;
-
// Lookup the first component from the alpha function table
- int compindex = bpmem.alpha_test.comp0;
+ int compindex = uid_data->alpha_test_comp0;
out.Write(tevAlphaFuncsTable[compindex], alphaRef[0]);
- out.Write("%s", tevAlphaFunclogicTable[bpmem.alpha_test.logic]); // lookup the logic op
+ out.Write("%s", tevAlphaFunclogicTable[uid_data->alpha_test_logic]); // lookup the logic op
// Lookup the second component from the alpha function table
- compindex = bpmem.alpha_test.comp1;
+ compindex = uid_data->alpha_test_comp1;
out.Write(tevAlphaFuncsTable[compindex], alphaRef[1]);
if (DriverDetails::HasBug(DriverDetails::BUG_BROKENNEGATEDBOOLEAN))
@@ -1113,16 +1207,6 @@ static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE Api
out.Write("\t\tdepth = %s;\n", (ApiType == API_D3D) ? "0.0" : "1.0");
// ZCOMPLOC HACK:
- // The only way to emulate alpha test + early-z is to force early-z in the shader.
- // As this isn't available on all drivers and as we can't emulate this feature otherwise,
- // we are only able to choose which one we want to respect more.
- // Tests seem to have proven that writing depth even when the alpha test fails is more
- // important that a reliable alpha test, so we just force the alpha test to always succeed.
- // At least this seems to be less buggy.
- uid_data->alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable &&
- !g_ActiveConfig.backend_info.bSupportsEarlyZ &&
- !bpmem.genMode.zfreeze;
-
if (!uid_data->alpha_test_use_zcomploc_hack)
{
out.Write("\t\tdiscard;\n");
@@ -1144,19 +1228,15 @@ static const char* tevFogFuncsTable[] = {
"\tfog = 1.0 - fog;\n fog = exp2(-8.0 * fog * fog);\n" // backward exp2
};
-template <class T>
-static void WriteFog(T& out, pixel_shader_uid_data* uid_data)
+static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
{
- uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
- if (bpmem.fog.c_proj_fsel.fsel == 0)
+ if (uid_data->fog_fsel == 0)
return; // no Fog
- uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj;
-
out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR);
out.SetConstantsUsed(C_FOGI, C_FOGI);
out.SetConstantsUsed(C_FOGF, C_FOGF + 1);
- if (bpmem.fog.c_proj_fsel.proj == 0)
+ if (uid_data->fog_proj == 0)
{
// perspective
// ze = A/(B - (Zs >> B_SHF)
@@ -1178,8 +1258,7 @@ static void WriteFog(T& out, pixel_shader_uid_data* uid_data)
// ze *= x_adjust
// TODO Instead of this theoretical calculation, we should use the
// coefficient table given in the fog range BP registers!
- uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled;
- if (bpmem.fogRange.Base.Enabled)
+ if (uid_data->fog_RangeBaseEnabled)
{
out.SetConstantsUsed(C_FOGF, C_FOGF);
out.Write("\tfloat x_adjust = (2.0 * (rawpos.x / " I_FOGF "[0].y)) - 1.0 - " I_FOGF "[0].x;\n");
@@ -1190,26 +1269,16 @@ static void WriteFog(T& out, pixel_shader_uid_data* uid_data)
out.Write("\tfloat fog = clamp(ze - " I_FOGF "[1].z, 0.0, 1.0);\n");
- if (bpmem.fog.c_proj_fsel.fsel > 3)
+ if (uid_data->fog_fsel > 3)
{
- out.Write("%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]);
+ out.Write("%s", tevFogFuncsTable[uid_data->fog_fsel]);
}
else
{
- if (bpmem.fog.c_proj_fsel.fsel != 2)
- WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel);
+ if (uid_data->fog_fsel != 2)
+ WARN_LOG(VIDEO, "Unknown Fog Type! %08x", uid_data->fog_fsel);
}
out.Write("\tint ifog = iround(fog * 256.0);\n");
out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR ".rgb * ifog) >> 8;\n");
}
-
-PixelShaderUid GetPixelShaderUid(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
-{
- return GeneratePixelShader<PixelShaderUid>(dstAlphaMode, ApiType);
-}
-
-ShaderCode GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
-{
- return GeneratePixelShader<ShaderCode>(dstAlphaMode, ApiType);
-}