summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/PixelShaderGen.cpp
diff options
context:
space:
mode:
authorTony Wasserka <neobrainx@gmail.com>2014-03-14 22:57:40 +0100
committerTony Wasserka <neobrainx@gmail.com>2014-03-14 22:57:40 +0100
commita9a8c730748b8c8a2e83feb4c38626361cf9daa1 (patch)
treeb847e06006198ac3d5b5dbb701ff4b1ab4e2de00 /Source/Core/VideoCommon/PixelShaderGen.cpp
parent450bde27bb2d7a47335c9800d3a29e012c9d67e9 (diff)
parent0f81cbd6be009ac14f036a05db8f4e516ea626d0 (diff)
Merge pull request #68 from neobrain/tev_fixes_new
Change pixel processing to use integer arithmetic.
Diffstat (limited to 'Source/Core/VideoCommon/PixelShaderGen.cpp')
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.cpp697
1 files changed, 267 insertions, 430 deletions
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index 9f634d4def..29399a253f 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -18,25 +18,16 @@
#include "VideoCommon/XFMemory.h" // for texture projection mode
-// old tev->pixelshader notes
-//
-// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0
-// konstant for this stage (alpha, color) is given by bpmem.tevksel
-// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current channel color
-// according to GXTevColorArg table above
-// output is given by .outreg
-// tevtemp is set according to swapmodetables and
-
-static const char *tevKSelTableC[] = // KCSEL
+static const char *tevKSelTableC[] =
{
- "1.0,1.0,1.0", // 1 = 0x00
- "0.875,0.875,0.875", // 7_8 = 0x01
- "0.75,0.75,0.75", // 3_4 = 0x02
- "0.625,0.625,0.625", // 5_8 = 0x03
- "0.5,0.5,0.5", // 1_2 = 0x04
- "0.375,0.375,0.375", // 3_8 = 0x05
- "0.25,0.25,0.25", // 1_4 = 0x06
- "0.125,0.125,0.125", // 1_8 = 0x07
+ "255,255,255", // 1 = 0x00
+ "223,223,223", // 7_8 = 0x01
+ "191,191,191", // 3_4 = 0x02
+ "159,159,159", // 5_8 = 0x03
+ "127,127,127", // 1_2 = 0x04
+ "95,95,95", // 3_8 = 0x05
+ "63,63,63", // 1_4 = 0x06
+ "31,31,31", // 1_8 = 0x07
"ERROR1", // 0x08
"ERROR2", // 0x09
"ERROR3", // 0x0a
@@ -63,16 +54,16 @@ static const char *tevKSelTableC[] = // KCSEL
I_KCOLORS"[3].aaa", // K3_A = 0x1F
};
-static const char *tevKSelTableA[] = // KASEL
+static const char *tevKSelTableA[] =
{
- "1.0", // 1 = 0x00
- "0.875",// 7_8 = 0x01
- "0.75", // 3_4 = 0x02
- "0.625",// 5_8 = 0x03
- "0.5", // 1_2 = 0x04
- "0.375",// 3_8 = 0x05
- "0.25", // 1_4 = 0x06
- "0.125",// 1_8 = 0x07
+ "255", // 1 = 0x00
+ "223", // 7_8 = 0x01
+ "191", // 3_4 = 0x02
+ "159", // 5_8 = 0x03
+ "127", // 1_2 = 0x04
+ "95", // 3_8 = 0x05
+ "63", // 1_4 = 0x06
+ "31", // 1_8 = 0x07
"ERROR5", // 0x08
"ERROR6", // 0x09
"ERROR7", // 0x0a
@@ -99,66 +90,48 @@ static const char *tevKSelTableA[] = // KASEL
I_KCOLORS"[3].a", // K3_A = 0x1F
};
-static const char *tevScaleTable[] = // CS
+static const char *tevScaleTable[] =
{
- "1.0", // SCALE_1
- "2.0", // SCALE_2
- "4.0", // SCALE_4
- "0.5", // DIVIDE_2
+ "", // SCALE_1
+ " << 1", // SCALE_2
+ " << 2", // SCALE_4
+ " >> 1", // DIVIDE_2
};
-static const char *tevBiasTable[] = // TB
+static const char *tevBiasTable[] =
{
"", // ZERO,
- "+0.5", // ADDHALF,
- "-0.5", // SUBHALF,
+ "+ 128", // ADDHALF,
+ "- 128", // SUBHALF,
"",
};
-static const char *tevOpTable[] = { // TEV
+static const char *tevOpTable[] = {
"+", // TEVOP_ADD = 0,
"-", // TEVOP_SUB = 1,
};
-static const char *tevCInputTable[] = // CC
+static const char *tevCInputTable[] =
{
- "(prev.rgb)", // CPREV,
- "(prev.aaa)", // APREV,
- "(c0.rgb)", // C0,
- "(c0.aaa)", // A0,
- "(c1.rgb)", // C1,
- "(c1.aaa)", // A1,
- "(c2.rgb)", // C2,
- "(c2.aaa)", // A2,
- "(textemp.rgb)", // TEXC,
- "(textemp.aaa)", // TEXA,
- "(rastemp.rgb)", // RASC,
- "(rastemp.aaa)", // RASA,
- "float3(1.0, 1.0, 1.0)", // ONE
- "float3(0.5, 0.5, 0.5)", // HALF
- "(konsttemp.rgb)", //"konsttemp.rgb", // KONST
- "float3(0.0, 0.0, 0.0)", // ZERO
- ///added extra values to map clamped values
- "(cprev.rgb)", // CPREV,
- "(cprev.aaa)", // APREV,
- "(cc0.rgb)", // C0,
- "(cc0.aaa)", // A0,
- "(cc1.rgb)", // C1,
- "(cc1.aaa)", // A1,
- "(cc2.rgb)", // C2,
- "(cc2.aaa)", // A2,
- "(textemp.rgb)", // TEXC,
- "(textemp.aaa)", // TEXA,
- "(crastemp.rgb)", // RASC,
- "(crastemp.aaa)", // RASA,
- "float3(1.0, 1.0, 1.0)", // ONE
- "float3(0.5, 0.5, 0.5)", // HALF
- "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST
- "float3(0.0, 0.0, 0.0)", // ZERO
- "PADERROR1", "PADERROR2", "PADERROR3", "PADERROR4"
+ "prev.rgb", // CPREV,
+ "prev.aaa", // APREV,
+ "c0.rgb", // C0,
+ "c0.aaa", // A0,
+ "c1.rgb", // C1,
+ "c1.aaa", // A1,
+ "c2.rgb", // C2,
+ "c2.aaa", // A2,
+ "textemp.rgb", // TEXC,
+ "textemp.aaa", // TEXA,
+ "rastemp.rgb", // RASC,
+ "rastemp.aaa", // RASA,
+ "int3(255,255,255)", // ONE
+ "int3(127,127,127)", // HALF
+ "konsttemp.rgb", // KONST
+ "int3(0,0,0)", // ZERO
};
-static const char *tevAInputTable[] = // CA
+static const char *tevAInputTable[] =
{
"prev", // APREV,
"c0", // A0,
@@ -167,54 +140,27 @@ static const char *tevAInputTable[] = // CA
"textemp", // TEXA,
"rastemp", // RASA,
"konsttemp", // KONST, (hw1 had quarter)
- "float4(0.0, 0.0, 0.0, 0.0)", // ZERO
- ///added extra values to map clamped values
- "cprev", // APREV,
- "cc0", // A0,
- "cc1", // A1,
- "cc2", // A2,
- "textemp", // TEXA,
- "crastemp", // RASA,
- "ckonsttemp", // KONST, (hw1 had quarter)
- "float4(0.0, 0.0, 0.0, 0.0)", // ZERO
- "PADERROR5", "PADERROR6", "PADERROR7", "PADERROR8",
- "PADERROR9", "PADERROR10", "PADERROR11", "PADERROR12",
+ "int4(0,0,0,0)", // ZERO
};
static const char *tevRasTable[] =
{
- "colors_0",
- "colors_1",
+ "int4(round(colors_0 * 255.0))",
+ "int4(round(colors_1 * 255.0))",
"ERROR13", //2
"ERROR14", //3
"ERROR15", //4
- "float4(alphabump,alphabump,alphabump,alphabump)", // use bump alpha
- "(float4(alphabump,alphabump,alphabump,alphabump)*(255.0/248.0))", //normalized
- "float4(0.0, 0.0, 0.0, 0.0)", // zero
+ "(int4(1, 1, 1, 1) * alphabump)", // bump alpha (0..248)
+ "(int4(1, 1, 1, 1) * (alphabump | (alphabump >> 5)))", // normalized bump alpha (0..255)
+ "int4(0, 0, 0, 0)", // zero
};
-//static const char *tevTexFunc[] = { "tex2D", "texRECT" };
-
static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" };
static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" };
-static const char *tevIndAlphaSel[] = {"", "x", "y", "z"};
-//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"};
-static const char *tevIndAlphaScale[] = {"*(248.0/255.0)", "*(224.0/255.0)", "*(240.0/255.0)", "*(248.0/255.0)"};
-static const char *tevIndBiasField[] = {"", "x", "y", "xy", "z", "xz", "yz", "xyz"}; // indexed by bias
-static const char *tevIndBiasAdd[] = {"-128.0", "1.0", "1.0", "1.0" }; // indexed by fmt
-static const char *tevIndWrapStart[] = {"0.0", "256.0", "128.0", "64.0", "32.0", "16.0", "0.001" };
-static const char *tevIndFmtScale[] = {"255.0", "31.0", "15.0", "7.0" };
-
-struct RegisterState
-{
- bool ColorNeedOverflowControl;
- bool AlphaNeedOverflowControl;
- bool AuxStored;
-};
static char text[16384];
-template<class T> static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4], const char swapModeTable[4][5]);
+template<class T> static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, const char swapModeTable[4][5]);
template<class T> static inline void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType);
template<class T> static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth);
template<class T> static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data);
@@ -257,6 +203,19 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
uid_data.genMode_numtevstages = bpmem.genMode.numtevstages;
uid_data.genMode_numtexgens = bpmem.genMode.numtexgens;
+ // dot product for integer vectors
+ 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");
+
if (ApiType == API_OPENGL)
{
// Fmod implementation gleaned from Nvidia
@@ -286,18 +245,21 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
if (ApiType == API_OPENGL)
out.Write("layout(std140%s) uniform PSBlock {\n", g_ActiveConfig.backend_info.bSupportShadingLanguage420pack ? ", binding = 1" : "");
- DeclareUniform(out, ApiType, C_COLORS, "float4", I_COLORS"[4]");
- DeclareUniform(out, ApiType, C_KCOLORS, "float4", I_KCOLORS"[4]");
- DeclareUniform(out, ApiType, C_ALPHA, "float4", I_ALPHA"[1]"); // TODO: Why is this an array...-.-
+ DeclareUniform(out, ApiType, C_COLORS, "int4", I_COLORS"[4]");
+ DeclareUniform(out, ApiType, C_KCOLORS, "int4", I_KCOLORS"[4]");
+ DeclareUniform(out, ApiType, C_ALPHA, "int4", I_ALPHA);
DeclareUniform(out, ApiType, C_TEXDIMS, "float4", I_TEXDIMS"[8]");
- DeclareUniform(out, ApiType, C_ZBIAS, "float4", I_ZBIAS"[2]");
- DeclareUniform(out, ApiType, C_INDTEXSCALE, "float4", I_INDTEXSCALE"[2]");
- DeclareUniform(out, ApiType, C_INDTEXMTX, "float4", I_INDTEXMTX"[6]");
- DeclareUniform(out, ApiType, C_FOG, "float4", I_FOG"[3]");
+ DeclareUniform(out, ApiType, C_ZBIAS, "int4", I_ZBIAS"[2]");
+ DeclareUniform(out, ApiType, C_INDTEXSCALE, "int4", I_INDTEXSCALE"[2]");
+ DeclareUniform(out, ApiType, C_INDTEXMTX, "int4", I_INDTEXMTX"[6]");
+ DeclareUniform(out, ApiType, C_FOGCOLOR, "int4", I_FOGCOLOR);
+ DeclareUniform(out, ApiType, C_FOGI, "int4", I_FOGI);
+ DeclareUniform(out, ApiType, C_FOGF, "float4", I_FOGF"[2]");
// For pixel lighting - TODO: Should only be defined when per pixel lighting is enabled!
- DeclareUniform(out, ApiType, C_PLIGHTS, "float4", I_PLIGHTS"[40]");
- DeclareUniform(out, ApiType, C_PMATERIALS, "float4", I_PMATERIALS"[4]");
+ DeclareUniform(out, ApiType, C_PLIGHT_COLORS, "int4", I_PLIGHT_COLORS"[8]");
+ DeclareUniform(out, ApiType, C_PLIGHTS, "float4", I_PLIGHTS"[32]");
+ DeclareUniform(out, ApiType, C_PMATERIALS, "int4", I_PMATERIALS"[4]");
if (ApiType == API_OPENGL)
out.Write("};\n");
@@ -376,35 +338,33 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
out.Write(" ) {\n");
}
- out.Write(" float4 c0 = " I_COLORS"[1], c1 = " I_COLORS"[2], c2 = " I_COLORS"[3], prev = float4(0.0, 0.0, 0.0, 0.0), textemp = float4(0.0, 0.0, 0.0, 0.0), rastemp = float4(0.0, 0.0, 0.0, 0.0), konsttemp = float4(0.0, 0.0, 0.0, 0.0);\n"
- " float3 comp16 = float3(1.0, 255.0, 0.0), comp24 = float3(1.0, 255.0, 255.0*255.0);\n"
- " float alphabump=0.0;\n"
- " float3 tevcoord=float3(0.0, 0.0, 0.0);\n"
- " float2 wrappedcoord=float2(0.0,0.0), tempcoord=float2(0.0,0.0);\n"
- " float4 cc0=float4(0.0,0.0,0.0,0.0), cc1=float4(0.0,0.0,0.0,0.0);\n"
- " float4 cc2=float4(0.0,0.0,0.0,0.0), cprev=float4(0.0,0.0,0.0,0.0);\n"
- " float4 crastemp=float4(0.0,0.0,0.0,0.0),ckonsttemp=float4(0.0,0.0,0.0,0.0);\n\n");
+ 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\n");
if (ApiType == API_OPENGL)
{
// On Mali, global variables must be initialized as constants.
// This is why we initialize these variables locally instead.
- out.Write("float4 rawpos = gl_FragCoord;\n");
- out.Write("float4 colors_0 = colors_02;\n");
- out.Write("float4 colors_1 = colors_12;\n");
+ out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
+ out.Write("\tfloat4 colors_0 = colors_02;\n");
+ out.Write("\tfloat4 colors_1 = colors_12;\n");
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
if (numTexgen)
{
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
{
- out.Write("float3 uv%d = uv%d_2;\n", i, i);
+ out.Write("\tfloat3 uv%d = uv%d_2;\n", i, i);
}
}
- out.Write("float4 clipPos = clipPos_2;\n");
+ out.Write("\tfloat4 clipPos = clipPos_2;\n");
if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
{
- out.Write("float4 Normal = Normal_2;\n");
+ out.Write("\tfloat4 Normal = Normal_2;\n");
}
}
@@ -413,14 +373,15 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
out.Write("\tfloat3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n");
- out.Write("\tfloat4 mat, lacc;\n"
+ out.Write("\tint4 lacc;\n"
"\tfloat3 ldir, h;\n"
"\tfloat dist, dist2, attn;\n");
- out.SetConstantsUsed(C_PLIGHTS, C_PLIGHTS+39); // TODO: Can be optimized further
+ 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, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_");
+ GenerateLightingShader<T>(out, uid_data.lighting, components, I_PMATERIALS, I_PLIGHT_COLORS, I_PLIGHTS, "colors_", "colors_");
}
out.Write("\tclipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n");
@@ -428,7 +389,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// HACK to handle cases where the tex gen is not enabled
if (numTexgen == 0)
{
- out.Write("\tfloat3 uv0 = float3(0.0, 0.0, 0.0);\n");
+ out.Write("\tint2 fixpoint_uv0 = int2(0, 0);\n\n");
}
else
{
@@ -439,11 +400,12 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
uid_data.texMtxInfo_n_projection |= xfregs.texMtxInfo[i].projection << i;
if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ)
{
- out.Write("\tif (uv%d.z != 0.0)", i);
+ out.Write("\tif (uv%d.z != 0.0)\n", i);
out.Write("\t\tuv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i);
}
- out.Write("uv%d.xy = uv%d.xy * " I_TEXDIMS"[%d].zw;\n", i, i, i);
+ out.Write("\tint2 fixpoint_uv%d = int2(round(uv%d.xy * " I_TEXDIMS"[%d].zw * 128.0));\n\n", i, i, i);
+ // TODO: S24 overflows here?
}
}
@@ -470,27 +432,16 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
if (texcoord < numTexgen)
{
out.SetConstantsUsed(C_INDTEXSCALE+i/2,C_INDTEXSCALE+i/2);
- out.Write("\ttempcoord = uv%d.xy * " I_INDTEXSCALE"[%d].%s;\n", texcoord, i/2, (i&1)?"zw":"xy");
+ out.Write("\ttempcoord = fixpoint_uv%d >> " I_INDTEXSCALE"[%d].%s;\n", texcoord, i / 2, (i & 1) ? "zw" : "xy");
}
else
- out.Write("\ttempcoord = float2(0.0, 0.0);\n");
+ out.Write("\ttempcoord = int2(0, 0);\n");
- out.Write("float3 indtex%d = ", i);
- SampleTexture<T>(out, "tempcoord", "abg", texmap, ApiType);
+ out.Write("\tint3 iindtex%d = ", i);
+ SampleTexture<T>(out, "(float2(tempcoord)/128.0)", "abg", texmap, ApiType);
}
}
- RegisterState RegisterStates[4];
- RegisterStates[0].AlphaNeedOverflowControl = false;
- RegisterStates[0].ColorNeedOverflowControl = false;
- RegisterStates[0].AuxStored = false;
- for (int i = 1; i < 4; i++)
- {
- RegisterStates[i].AlphaNeedOverflowControl = true;
- RegisterStates[i].ColorNeedOverflowControl = true;
- RegisterStates[i].AuxStored = false;
- }
-
// Uid fields for BuildSwapModeTable are set in WriteStage
char swapModeTable[4][5];
const char* swapColors = "rgba";
@@ -504,7 +455,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
}
for (unsigned int i = 0; i < numStages; i++)
- WriteStage<T>(out, uid_data, i, ApiType, RegisterStates, swapModeTable); // build the equation for this stage
+ WriteStage<T>(out, uid_data, i, ApiType, swapModeTable); // build the equation for this stage
#define MY_STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str)))
bool enable_pl = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting;
@@ -517,20 +468,14 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// regardless of the used destination register
if (bpmem.combiners[numStages - 1].colorC.dest != 0)
{
- bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].AuxStored;
- out.Write("\tprev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]);
- RegisterStates[0].ColorNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl;
+ out.Write("\tprev.rgb = %s;\n", tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]);
}
if (bpmem.combiners[numStages - 1].alphaC.dest != 0)
{
- bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AuxStored;
- out.Write("\tprev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]);
- RegisterStates[0].AlphaNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl;
+ out.Write("\tprev.a = %s;\n", tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]);
}
}
- // emulation of unsigned 8 overflow when casting if needed
- if (RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
- out.Write("\tprev = frac(prev * (255.0/256.0)) * (256.0/255.0);\n");
+ out.Write("\tprev = prev & 255;\n");
AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult();
uid_data.Pretest = Pretest;
@@ -546,12 +491,12 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// The performance impact of this additional calculation doesn't matter, but it prevents
// the host GPU driver from performing any early depth test optimizations.
if (g_ActiveConfig.bFastDepthCalc)
- out.Write("float zCoord = rawpos.z;\n");
+ out.Write("\tint zCoord = int(round(rawpos.z * float(0xFFFFFF)));\n");
else
{
out.SetConstantsUsed(C_ZBIAS+1, C_ZBIAS+1);
// the screen space depth value = far z + (clip z / clip w) * z range
- out.Write("float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n");
+ out.Write("\tint zCoord = " I_ZBIAS"[1].x + int(round((clipPos.z / clipPos.w) * float(" I_ZBIAS"[1].y)));\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
@@ -566,7 +511,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// Note: z-textures are not written to depth buffer if early depth test is used
if (per_pixel_depth && bpmem.UseEarlyDepthTest())
- out.Write("depth = zCoord;\n");
+ out.Write("\tdepth = float(zCoord) / float(0xFFFFFF);\n");
// 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
@@ -574,27 +519,23 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
{
// 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("zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w %s;\n",
+ out.Write("\tzCoord = idot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w %s;\n",
(bpmem.ztex2.op == ZTEXTURE_ADD) ? "+ zCoord" : "");
-
- // U24 overflow emulation
- out.Write("zCoord = zCoord * (16777215.0/16777216.0);\n");
- out.Write("zCoord = frac(zCoord);\n");
- out.Write("zCoord = zCoord * (16777216.0/16777215.0);\n");
+ out.Write("\tzCoord = zCoord & 0xFFFFFF;\n");
}
if (per_pixel_depth && bpmem.UseLateDepthTest())
- out.Write("depth = zCoord;\n");
+ out.Write("\tdepth = float(zCoord) / float(0xFFFFFF);\n");
if (dstAlphaMode == DSTALPHA_ALPHA_PASS)
{
out.SetConstantsUsed(C_ALPHA, C_ALPHA);
- out.Write("\tocol0 = float4(prev.rgb, " I_ALPHA"[0].a);\n");
+ out.Write("\tocol0 = float4(float3(prev.rgb), float(" I_ALPHA".a)) / 255.0;\n");
}
else
{
WriteFog<T>(out, uid_data);
- out.Write("\tocol0 = prev;\n");
+ out.Write("\tocol0 = float4(prev) / 255.0;\n");
}
// Use dual-source color blending to perform dst alpha in a single pass
@@ -604,8 +545,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// Colors will be blended against the alpha from ocol1 and
// the alpha from ocol0 will be written to the framebuffer.
- out.Write("\tocol1 = prev;\n");
- out.Write("\tocol0.a = " I_ALPHA"[0].a;\n");
+ out.Write("\tocol1 = float4(prev) / 255.0;\n");
+ out.Write("\tocol0.a = float(" I_ALPHA".a) / 255.0;\n");
}
out.Write("}\n");
@@ -623,51 +564,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
}
-
-//table with the color compare operations
-static const char *TEVCMPColorOPTable[16] =
-{
- "float3(0.0, 0.0, 0.0)",//0
- "float3(0.0, 0.0, 0.0)",//1
- "float3(0.0, 0.0, 0.0)",//2
- "float3(0.0, 0.0, 0.0)",//3
- "float3(0.0, 0.0, 0.0)",//4
- "float3(0.0, 0.0, 0.0)",//5
- "float3(0.0, 0.0, 0.0)",//6
- "float3(0.0, 0.0, 0.0)",//7
- " %s + ((%s.r >= %s.r + (0.25/255.0)) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_R8_GT 8
- " %s + ((abs(%s.r - %s.r) < (0.5/255.0)) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_R8_EQ 9
- " %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25/255.0))) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_GR16_GT 10
- " %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5/255.0) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_GR16_EQ 11
- " %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25/255.0))) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_BGR24_GT 12
- " %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5/255.0) ? %s : float3(0.0, 0.0, 0.0))",//#define TEVCMP_BGR24_EQ 13
- " %s + (max(sign(%s.rgb - %s.rgb - (0.25/255.0)), float3(0.0, 0.0, 0.0)) * %s)",//#define TEVCMP_RGB8_GT 14
- " %s + ((float3(1.0, 1.0, 1.0) - max(sign(abs(%s.rgb - %s.rgb) - (0.5/255.0)), float3(0.0, 0.0, 0.0))) * %s)"//#define TEVCMP_RGB8_EQ 15
-};
-
-//table with the alpha compare operations
-static const char *TEVCMPAlphaOPTable[16] =
-{
- "0.0",//0
- "0.0",//1
- "0.0",//2
- "0.0",//3
- "0.0",//4
- "0.0",//5
- "0.0",//6
- "0.0",//7
- " %s.a + ((%s.r >= (%s.r + (0.25/255.0))) ? %s.a : 0.0)",//#define TEVCMP_R8_GT 8
- " %s.a + (abs(%s.r - %s.r) < (0.5/255.0) ? %s.a : 0.0)",//#define TEVCMP_R8_EQ 9
- " %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25/255.0))) ? %s.a : 0.0)",//#define TEVCMP_GR16_GT 10
- " %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5/255.0) ? %s.a : 0.0)",//#define TEVCMP_GR16_EQ 11
- " %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25/255.0))) ? %s.a : 0.0)",//#define TEVCMP_BGR24_GT 12
- " %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5/255.0) ? %s.a : 0.0)",//#define TEVCMP_BGR24_EQ 13
- " %s.a + ((%s.a >= (%s.a + (0.25/255.0))) ? %s.a : 0.0)",//#define TEVCMP_A8_GT 14
- " %s.a + (abs(%s.a - %s.a) < (0.5/255.0) ? %s.a : 0.0)"//#define TEVCMP_A8_EQ 15
-};
-
template<class T>
-static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4], const char swapModeTable[4][5])
+static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, const char swapModeTable[4][5])
{
int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1);
bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens;
@@ -676,7 +574,7 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
if (!bHasTexCoord)
texcoord = 0;
- out.Write("// TEV stage %d\n", n);
+ out.Write("\t// TEV stage %d\n", n);
uid_data.stagehash[n].hasindstage = bHasIndStage;
uid_data.stagehash[n].tevorders_texcoord = texcoord;
@@ -684,80 +582,109 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
{
uid_data.stagehash[n].tevind = bpmem.tevind[n].hex & 0x7FFFFF;
- out.Write("// indirect op\n");
- // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords
+ 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)
{
- out.Write("alphabump = indtex%d.%s %s;\n",
+ 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],
- tevIndAlphaScale[bpmem.tevind[n].fmt]);
+ tevIndAlphaMask[bpmem.tevind[n].fmt]);
+ }
+ else
+ {
+ // TODO: Should we reset alphabump to 0 here?
}
- // format
- out.Write("float3 indtevcrd%d = indtex%d * %s;\n", n, bpmem.tevind[n].bt, tevIndFmtScale[bpmem.tevind[n].fmt]);
-
- // bias
- if (bpmem.tevind[n].bias != ITB_NONE )
- out.Write("indtevcrd%d.%s += %s;\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]);
- // multiply by offset matrix and scale
+ // 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]);
+
+ // 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]);
+
+ // 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 != 0)
{
if (bpmem.tevind[n].mid <= 3)
{
int mtxidx = 2*(bpmem.tevind[n].mid-1);
out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx);
- out.Write("float2 indtevtrans%d = float2(dot(" I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot(" I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n",
- n, mtxidx, n, mtxidx+1, n);
+
+ out.Write("\tint2 indtevtrans%d = int2(idot(" I_INDTEXMTX"[%d].xyz, iindtevcrd%d), idot(" I_INDTEXMTX"[%d].xyz, iindtevcrd%d)) >> 3;\n", n, mtxidx, n, mtxidx+1, n);
+
+ // TODO: should use a shader uid branch for this for better performance
+ out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX"[%d].w;\n", mtxidx, n, n, mtxidx);
+ out.Write("\telse indtevtrans%d = indtevtrans%d << (-" I_INDTEXMTX"[%d].w);\n", n, n, mtxidx);
}
else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord)
{ // s matrix
_assert_(bpmem.tevind[n].mid >= 5);
int mtxidx = 2*(bpmem.tevind[n].mid-5);
out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx);
- out.Write("float2 indtevtrans%d = " I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n);
+ out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.xx) >> 8;\n", n, texcoord, n);
+
+ out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX"[%d].w;\n", mtxidx, n, n, mtxidx);
+ out.Write("\telse indtevtrans%d = indtevtrans%d << (-" I_INDTEXMTX"[%d].w);\n", n, n, mtxidx);
}
else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord)
{ // t matrix
_assert_(bpmem.tevind[n].mid >= 9);
int mtxidx = 2*(bpmem.tevind[n].mid-9);
out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx);
- out.Write("float2 indtevtrans%d = " I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n);
+ out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.yy) >> 8;\n", n, texcoord, n);
+
+ out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX"[%d].w;\n", mtxidx, n, n, mtxidx);
+ out.Write("\telse indtevtrans%d = indtevtrans%d << (-" I_INDTEXMTX"[%d].w);\n", n, n, mtxidx);
}
else
{
- out.Write("float2 indtevtrans%d = float2(0.0, 0.0);\n", n);
+ out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n);
}
}
else
{
- out.Write("float2 indtevtrans%d = float2(0.0, 0.0);\n", n);
+ out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n);
}
// ---------
// Wrapping
// ---------
+ const char *tevIndWrapStart[] = {"0", "(256<<7)", "(128<<7)", "(64<<7)", "(32<<7)", "(16<<7)", "1" }; // TODO: Should the last one be 1 or (1<<7)?
// wrap S
if (bpmem.tevind[n].sw == ITW_OFF)
- out.Write("wrappedcoord.x = uv%d.x;\n", texcoord);
+ out.Write("\twrappedcoord.x = fixpoint_uv%d.x;\n", texcoord);
else if (bpmem.tevind[n].sw == ITW_0)
- out.Write("wrappedcoord.x = 0.0;\n");
+ out.Write("\twrappedcoord.x = 0;\n");
else
- out.Write("wrappedcoord.x = fmod( uv%d.x, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]);
+ out.Write("\twrappedcoord.x = fixpoint_uv%d.x %% %s;\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]);
// wrap T
if (bpmem.tevind[n].tw == ITW_OFF)
- out.Write("wrappedcoord.y = uv%d.y;\n", texcoord);
+ out.Write("\twrappedcoord.y = fixpoint_uv%d.y;\n", texcoord);
else if (bpmem.tevind[n].tw == ITW_0)
- out.Write("wrappedcoord.y = 0.0;\n");
+ out.Write("\twrappedcoord.y = 0;\n");
else
- out.Write("wrappedcoord.y = fmod( uv%d.y, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]);
+ out.Write("\twrappedcoord.y = fixpoint_uv%d.y %% %s;\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]);
if (bpmem.tevind[n].fb_addprev) // add previous tevcoord
- out.Write("tevcoord.xy += wrappedcoord + indtevtrans%d;\n", n);
+ out.Write("\ttevcoord.xy += wrappedcoord + indtevtrans%d;\n", n);
else
- out.Write("tevcoord.xy = wrappedcoord + indtevtrans%d;\n", n);
+ out.Write("\ttevcoord.xy = wrappedcoord + indtevtrans%d;\n", n);
+
+ // Emulate s24 overflows
+ out.Write("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n");
}
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC;
@@ -782,20 +709,20 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
uid_data.stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1);
const char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap];
- out.Write("rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap);
- out.Write("crastemp = frac(rastemp * (255.0/256.0)) * (256.0/255.0);\n");
+ out.Write("\trastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap);
}
uid_data.stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1);
if (bpmem.tevorders[n/2].getEnable(n&1))
{
+ int texmap = bpmem.tevorders[n/2].getTexMap(n&1);
if (!bHasIndStage)
{
// calc tevcord
if (bHasTexCoord)
- out.Write("tevcoord.xy = uv%d.xy;\n", texcoord);
+ out.Write("\ttevcoord.xy = fixpoint_uv%d;\n", texcoord);
else
- out.Write("tevcoord.xy = float2(0.0, 0.0);\n");
+ out.Write("\ttevcoord.xy = int2(0, 0);\n");
}
const int i = bpmem.combiners[n].alphaC.tswap;
@@ -808,15 +735,14 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
uid_data.stagehash[n].tevorders_texmap= bpmem.tevorders[n/2].getTexMap(n&1);
const char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap];
- int texmap = bpmem.tevorders[n/2].getTexMap(n&1);
uid_data.SetTevindrefTexmap(i, texmap);
- out.Write("textemp = ");
- SampleTexture<T>(out, "tevcoord", texswap, texmap, ApiType);
+ out.Write("\ttextemp = ");
+ SampleTexture<T>(out, "(float2(tevcoord.xy)/128.0)", texswap, texmap, ApiType);
}
else
{
- out.Write("textemp = float4(1.0, 1.0, 1.0, 1.0);\n");
+ out.Write("\ttextemp = int4(255, 255, 255, 255);\n");
}
@@ -829,103 +755,14 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
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("konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]);
- if (kc > 7 || ka > 7)
- {
- out.Write("ckonsttemp = frac(konsttemp * (255.0/256.0)) * (256.0/255.0);\n");
- }
- else
- {
- out.Write("ckonsttemp = konsttemp;\n");
- }
+ 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));
}
- if (cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV ||
- cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV ||
- cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV ||
- ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV ||
- ac.c == TEVALPHAARG_APREV)
- {
- if (RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
- {
- out.Write("cprev = frac(prev * (255.0/256.0)) * (256.0/255.0);\n");
- RegisterStates[0].AlphaNeedOverflowControl = false;
- RegisterStates[0].ColorNeedOverflowControl = false;
- }
- else
- {
- out.Write("cprev = prev;\n");
- }
- RegisterStates[0].AuxStored = true;
- }
-
- if (cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 ||
- cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 ||
- cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 ||
- ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 ||
- ac.c == TEVALPHAARG_A0)
- {
- out.SetConstantsUsed(C_COLORS+1,C_COLORS+1);
- if (RegisterStates[1].AlphaNeedOverflowControl || RegisterStates[1].ColorNeedOverflowControl)
- {
- out.Write("cc0 = frac(c0 * (255.0/256.0)) * (256.0/255.0);\n");
- RegisterStates[1].AlphaNeedOverflowControl = false;
- RegisterStates[1].ColorNeedOverflowControl = false;
- }
- else
- {
- out.Write("cc0 = c0;\n");
- }
- RegisterStates[1].AuxStored = true;
- }
-
- if (cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 ||
- cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 ||
- cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 ||
- ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 ||
- ac.c == TEVALPHAARG_A1)
- {
- out.SetConstantsUsed(C_COLORS+2,C_COLORS+2);
- if (RegisterStates[2].AlphaNeedOverflowControl || RegisterStates[2].ColorNeedOverflowControl)
- {
- out.Write("cc1 = frac(c1 * (255.0/256.0)) * (256.0/255.0);\n");
- RegisterStates[2].AlphaNeedOverflowControl = false;
- RegisterStates[2].ColorNeedOverflowControl = false;
- }
- else
- {
- out.Write("cc1 = c1;\n");
- }
- RegisterStates[2].AuxStored = true;
- }
-
- if (cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 ||
- cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 ||
- cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 ||
- ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 ||
- ac.c == TEVALPHAARG_A2)
- {
- out.SetConstantsUsed(C_COLORS+3,C_COLORS+3);
- if (RegisterStates[3].AlphaNeedOverflowControl || RegisterStates[3].ColorNeedOverflowControl)
- {
- out.Write("cc2 = frac(c2 * (255.0/256.0)) * (256.0/255.0);\n");
- RegisterStates[3].AlphaNeedOverflowControl = false;
- RegisterStates[3].ColorNeedOverflowControl = false;
- }
- else
- {
- out.Write("cc2 = c2;\n");
- }
- RegisterStates[3].AuxStored = true;
- }
-
- RegisterStates[cc.dest].ColorNeedOverflowControl = (cc.clamp == 0);
- RegisterStates[cc.dest].AuxStored = false;
-
if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0)
out.SetConstantsUsed(C_COLORS+1,C_COLORS+1);
@@ -941,125 +778,118 @@ static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, AP
if (ac.dest >= GX_TEVREG0 && ac.dest <= GX_TEVREG2)
out.SetConstantsUsed(C_COLORS+ac.dest, C_COLORS+ac.dest);
- out.Write("// color combine\n");
- if (cc.clamp)
- out.Write("%s = clamp(", tevCOutputTable[cc.dest]);
- else
- out.Write("%s = ", tevCOutputTable[cc.dest]);
+ out.Write("\t// color combine\n");
+ out.Write("\t%s = clamp(", tevCOutputTable[cc.dest]);
// combine the color channel
if (cc.bias != TevBias_COMPARE) // if not compare
{
//normal color combiner goes here
if (cc.shift > TEVSCALE_1)
- out.Write("%s*(", tevScaleTable[cc.shift]);
+ out.Write("(");
if (!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD))
- out.Write("%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]);
-
- if (cc.a == cc.b)
- out.Write("%s", tevCInputTable[cc.a + 16]);
- else if (cc.c == TEVCOLORARG_ZERO)
- out.Write("%s", tevCInputTable[cc.a + 16]);
- else if (cc.c == TEVCOLORARG_ONE)
- out.Write("%s", tevCInputTable[cc.b + 16]);
- else if (cc.a == TEVCOLORARG_ZERO)
- out.Write("%s*%s", tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]);
- else if (cc.b == TEVCOLORARG_ZERO)
- out.Write("%s*(float3(1.0, 1.0, 1.0)-%s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.c + 16]);
- else
- out.Write("lerp(%s, %s, %s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]);
+ out.Write("%s %s ", tevCInputTable[cc.d], tevOpTable[cc.op]);
+
+ out.Write("((%s&255) * (int3(255,255,255) - (%s&255)) + (%s&255) * (%s&255)) / 255", tevCInputTable[cc.a], tevCInputTable[cc.c], tevCInputTable[cc.b], tevCInputTable[cc.c]);
- out.Write("%s", tevBiasTable[cc.bias]);
+ out.Write(" %s", tevBiasTable[cc.bias]);
if (cc.shift > TEVSCALE_1)
- out.Write(")");
+ out.Write(")%s", tevScaleTable[cc.shift]);
}
else
{
- int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here
- out.Write(TEVCMPColorOPTable[cmp],//lookup the function from the op table
- tevCInputTable[cc.d],
- tevCInputTable[cc.a + 16],
- tevCInputTable[cc.b + 16],
- tevCInputTable[cc.c + 16]);
+ const char *function_table[] =
+ {
+ "(((%s.r&255) > %s.r) ? (%s&255): int3(0,0,0))", // TEVCMP_R8_GT
+ "(((%s.r&255) == %s.r) ? (%s&255): int3(0,0,0))", // TEVCMP_R8_EQ
+ "((idot((%s.rgb&255), comp16) > idot((%s.rgb&255), comp16)) ? (%s&255): int3(0,0,0))", // TEVCMP_GR16_GT
+ "((idot((%s.rgb&255), comp16) == idot((%s.rgb&255), comp16)) ? (%s&255): int3(0,0,0))", // TEVCMP_GR16_EQ
+ "((idot((%s.rgb&255), comp24) > idot((%s.rgb&255), comp24)) ? (%s&255): int3(0,0,0))", // TEVCMP_BGR24_GT
+ "((idot((%s.rgb&255), comp24) == idot((%s.rgb&255), comp24)) ? (%s&255): int3(0,0,0))", // TEVCMP_BGR24_EQ
+ "int3(max(sign(int3((%s.rgb&255)) - int3((%s.rgb&255))), int3(0,0,0)) * (%s&255))", // TEVCMP_RGB8_GT
+ "int3((int3(255,255,255) - max(sign(abs(int3((%s.rgb&255)) - int3((%s.rgb&255)))), int3(0,0,0))) * (%s&255))" // TEVCMP_RGB8_EQ
+ };
+
+ int mode = (cc.shift<<1)|cc.op;
+ out.Write(" %s + ", tevCInputTable[cc.d]);
+ out.Write(function_table[mode], tevCInputTable[cc.a],
+ tevCInputTable[cc.b], tevCInputTable[cc.c]);
}
if (cc.clamp)
- out.Write(", 0.0, 1.0)");
+ out.Write(", int3(0,0,0), int3(255,255,255))");
+ else
+ out.Write(", int3(-1024,-1024,-1024), int3(1023,1023,1023))");
out.Write(";\n");
- RegisterStates[ac.dest].AlphaNeedOverflowControl = (ac.clamp == 0);
- RegisterStates[ac.dest].AuxStored = false;
-
- out.Write("// alpha combine\n");
- if (ac.clamp)
- out.Write("%s = clamp(", tevAOutputTable[ac.dest]);
- else
- out.Write("%s = ", tevAOutputTable[ac.dest]);
+ out.Write("\t// alpha combine\n");
+ out.Write("\t%s = clamp(", tevAOutputTable[ac.dest]);
if (ac.bias != TevBias_COMPARE) // if not compare
{
//normal alpha combiner goes here
- if (ac.shift > TEVSCALE_1)
- out.Write("%s*(", tevScaleTable[ac.shift]);
+ if (ac.shift > 0)
+ out.Write("(");
if (!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD))
- out.Write("%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]);
-
- if (ac.a == ac.b)
- out.Write("%s.a", tevAInputTable[ac.a + 8]);
- else if (ac.c == TEVALPHAARG_ZERO)
- out.Write("%s.a", tevAInputTable[ac.a + 8]);
- else if (ac.a == TEVALPHAARG_ZERO)
- out.Write("%s.a*%s.a", tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]);
- else if (ac.b == TEVALPHAARG_ZERO)
- out.Write("%s.a*(1.0-%s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.c + 8]);
- else
- out.Write("lerp(%s.a, %s.a, %s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]);
+ out.Write("%s.a %s ", tevAInputTable[ac.d], tevOpTable[ac.op]);
- out.Write("%s",tevBiasTable[ac.bias]);
+ out.Write("((%s.a&255) * (255 - (%s.a&255)) + (%s.a&255) * (%s.a&255)) / 255", tevAInputTable[ac.a], tevAInputTable[ac.c], tevAInputTable[ac.b], tevAInputTable[ac.c]);
- if (ac.shift>0)
- out.Write(")");
+ out.Write(" %s",tevBiasTable[ac.bias]);
+ if (ac.shift>0)
+ out.Write(")%s", tevScaleTable[ac.shift]);
}
else
{
- //compare alpha combiner goes here
- int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here
- out.Write(TEVCMPAlphaOPTable[cmp],
- tevAInputTable[ac.d],
- tevAInputTable[ac.a + 8],
- tevAInputTable[ac.b + 8],
- tevAInputTable[ac.c + 8]);
+ const char *function_table[] =
+ {
+ "(((%s.r&255) > (%s.r&255)) ? (%s.a&255) : 0)", // TEVCMP_R8_GT
+ "(((%s.r&255) == (%s.r&255)) ? (%s.a&255) : 0)", // TEVCMP_R8_EQ
+ "((idot((%s.rgb&255), comp16) > idot((%s.rgb&255), comp16)) ? (%s.a&255) : 0)", // TEVCMP_GR16_GT
+ "((idot((%s.rgb&255), comp16) == idot((%s.rgb&255), comp16)) ? (%s.a&255) : 0)", // TEVCMP_GR16_EQ
+ "((idot((%s.rgb&255), comp24) > idot((%s.rgb&255), comp24)) ? (%s.a&255) : 0)", // TEVCMP_BGR24_GT
+ "((idot((%s.rgb&255), comp24) == idot((%s.rgb&255), comp24)) ? (%s.a&255) : 0)", // TEVCMP_BGR24_EQ
+ "(((%s.a&255) > (%s.a&255)) ? (%s.a&255) : 0)", // TEVCMP_A8_GT
+ "(((%s.a&255) == (%s.a&255)) ? (%s.a&255) : 0)" // TEVCMP_A8_EQ
+ };
+
+ int mode = (ac.shift<<1)|ac.op;
+ out.Write(" %s.a + ", tevAInputTable[ac.d]);
+ out.Write(function_table[mode], tevAInputTable[ac.a],
+ tevAInputTable[ac.b], tevAInputTable[ac.c]);
}
if (ac.clamp)
- out.Write(", 0.0, 1.0)");
+ out.Write(", 0, 255)");
+ else
+ out.Write(", -1024, 1023)");
+
out.Write(";\n\n");
- out.Write("// TEV done\n");
}
template<class T>
-void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType)
+static inline void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType)
{
out.SetConstantsUsed(C_TEXDIMS+texmap,C_TEXDIMS+texmap);
if (ApiType == API_D3D)
- out.Write("Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", texmap,texmap, texcoords, texmap, texswap);
- else // OGL
- out.Write("texture(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", texmap, texcoords, texmap, texswap);
+ out.Write("int4(round(255.0 * Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy))).%s;\n", texmap,texmap, texcoords, texmap, texswap);
+ else
+ out.Write("int4(round(255.0 * texture(samp%d,%s.xy * " I_TEXDIMS"[%d].xy))).%s;\n", texmap, texcoords, texmap, texswap);
}
static const char *tevAlphaFuncsTable[] =
{
- "(false)", // NEVER
- "(prev.a <= %s - (0.25/255.0))", // LESS
- "(abs( prev.a - %s ) < (0.5/255.0))", // EQUAL
- "(prev.a < %s + (0.25/255.0))", // LEQUAL
- "(prev.a >= %s + (0.25/255.0))", // GREATER
- "(abs( prev.a - %s ) >= (0.5/255.0))", // NEQUAL
- "(prev.a > %s - (0.25/255.0))", // GEQUAL
- "(true)" // ALWAYS
+ "(false)", // NEVER
+ "(prev.a < %s)", // LESS
+ "(prev.a == %s)", // EQUAL
+ "(prev.a <= %s)", // LEQUAL
+ "(prev.a > %s)", // GREATER
+ "(prev.a != %s)", // NEQUAL
+ "(prev.a >= %s)", // GEQUAL
+ "(true)" // ALWAYS
};
static const char *tevAlphaFunclogicTable[] =
@@ -1075,8 +905,8 @@ static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_T
{
static const char *alphaRef[2] =
{
- I_ALPHA"[0].r",
- I_ALPHA"[0].g"
+ I_ALPHA".r",
+ I_ALPHA".g"
};
out.SetConstantsUsed(C_ALPHA, C_ALPHA);
@@ -1091,7 +921,7 @@ static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_T
int compindex = bpmem.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[bpmem.alpha_test.logic]); // lookup the logic op
// Lookup the second component from the alpha function table
compindex = bpmem.alpha_test.comp1;
@@ -1149,33 +979,39 @@ static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data)
uid_data.fog_proj = bpmem.fog.c_proj_fsel.proj;
- out.SetConstantsUsed(C_FOG, C_FOG+1);
+ 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)
{
// perspective
// ze = A/(B - (Zs >> B_SHF)
- out.Write("\tfloat ze = " I_FOG"[1].x / (" I_FOG"[1].y - (zCoord / " I_FOG"[1].w));\n");
+ // TODO: Verify that we want to drop lower bits here! (currently taken over from software 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.Write("\tfloat ze = (" I_FOGF"[1].x * 16777215.0) / float(" I_FOGI".y - (zCoord >> " I_FOGI".w));\n");
}
else
{
// orthographic
// ze = a*Zs (here, no B_SHF)
- out.Write("\tfloat ze = " I_FOG"[1].x * zCoord;\n");
+ out.Write("\tfloat ze = " I_FOGF"[1].x * float(zCoord) / 16777215.0;\n");
}
// x_adjust = sqrt((x-center)^2 + k^2)/k
// ze *= x_adjust
- // this is completely theoretical as the real hardware seems to use a table intead of calculating the values.
+ // 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)
{
- out.SetConstantsUsed(C_FOG+2, C_FOG+2);
- out.Write("\tfloat x_adjust = (2.0 * (clipPos.x / " I_FOG"[2].y)) - 1.0 - " I_FOG"[2].x;\n");
- out.Write("\tx_adjust = sqrt(x_adjust * x_adjust + " I_FOG"[2].z * " I_FOG"[2].z) / " I_FOG"[2].z;\n");
+ out.SetConstantsUsed(C_FOGF, C_FOGF);
+ out.Write("\tfloat x_adjust = (2.0 * (clipPos.x / " I_FOGF"[0].y)) - 1.0 - " I_FOGF"[0].x;\n");
+ out.Write("\tx_adjust = sqrt(x_adjust * x_adjust + " I_FOGF"[0].z * " I_FOGF"[0].z) / " I_FOGF"[0].z;\n");
out.Write("\tze *= x_adjust;\n");
}
- out.Write("\tfloat fog = clamp(ze - " I_FOG"[1].z, 0.0, 1.0);\n");
+ out.Write("\tfloat fog = clamp(ze - " I_FOGF"[1].z, 0.0, 1.0);\n");
if (bpmem.fog.c_proj_fsel.fsel > 3)
{
@@ -1187,7 +1023,8 @@ static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data)
WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel);
}
- out.Write("\tprev.rgb = lerp(prev.rgb, " I_FOG"[0].rgb, fog);\n");
+ out.Write("\tint ifog = int(round(fog * 256.0));\n");
+ out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR".rgb * ifog) >> 8;\n");
}
void GetPixelShaderUid(PixelShaderUid& object, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components)