diff --git a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl index 3ec0a0c71..d51819b6b 100644 --- a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl +++ b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl @@ -61,6 +61,10 @@ uniform const float FRONTFACE_FACTOR : register(c27); // Note : PSH_XBOX_CONSTA #if 0 // Compiler-defines/symbols which must be defined when their bit/value is set in the corresponding register : + // Generated by PixelShader.cpp::BuildShader() + + // Data from X_D3DTSS_ALPHAKILL : + #define ALPHAKILL {false, false, false, false} // Bits from PSCombinerCount (a.k.a. PSCombinerCountFlags) : #define PS_COMBINERCOUNT 2 @@ -74,10 +78,10 @@ uniform const float FRONTFACE_FACTOR : register(c27); // Note : PSH_XBOX_CONSTA #define PS_COMPAREMODE_2(in) CM_LT(in.x) CM_LT(in.y) CM_LT(in.z) CM_LT(in.w) #define PS_COMPAREMODE_3(in) CM_LT(in.x) CM_LT(in.y) CM_LT(in.z) CM_LT(in.w) - // Input texture register mappings for stage 1, 2 and 3 (stage 0 has no input-texture) + // Input texture register mappings for texture stage 1, 2 and 3 (stage 0 has no input-texture) static const int PS_INPUTTEXTURE_[4] = { -1, 0, 0, 0 }; - // Dot mappings for stage 1, 2 and 3 (stage 0 performs no dot product) + // Dot mappings for texture stage 1, 2 and 3 (stage 0 performs no dot product) #define PS_DOTMAPPING_1 PS_DOTMAPPING_MINUS1_TO_1_D3D #define PS_DOTMAPPING_2 PS_DOTMAPPING_MINUS1_TO_1_D3D #define PS_DOTMAPPING_3 PS_DOTMAPPING_MINUS1_TO_1_D3D @@ -93,14 +97,14 @@ uniform const float FRONTFACE_FACTOR : register(c27); // Note : PSH_XBOX_CONSTA // Second raw string : R"DELIMITER( -// PS_COMBINERCOUNT_UNIQUE_C0 steers whether for C0 to use stage-specific constants c0_0 .. c0_7, or c0_0 for all stages +// PS_COMBINERCOUNT_UNIQUE_C0 steers whether for C0 to use combiner stage-specific constants c0_0 .. c0_7, or c0_0 for all stages #ifdef PS_COMBINERCOUNT_UNIQUE_C0 #define C0 c0_[stage] // concatenate stage to form c0_0 .. c0_7 #else // PS_COMBINERCOUNT_SAME_C0 #define C0 c0_[0] // always resolve to c0_0 #endif -// PS_COMBINERCOUNT_UNIQUE_C1 steers whether for C1 to use stage-specific constants c1_0 .. c1_7, or c1_0 for all stages +// PS_COMBINERCOUNT_UNIQUE_C1 steers whether for C1 to use combiner stage-specific constants c1_0 .. c1_7, or c1_0 for all stages #ifdef PS_COMBINERCOUNT_UNIQUE_C1 #define C1 c1_[stage] // concatenate stage to form c1_0 .. c1_7 #else // PS_COMBINERCOUNT_SAME_C1 @@ -218,35 +222,38 @@ float m21(const float input) // TODO : Generate sampler status? sampler samplers[4] : register(s0); -// Generated alphakill contents are based on X_D3DTSS_ALPHAKILL (we avoid using a constant, to allow false's to be optimized away) -// bool alphakill[4] = {false, false, false, false}; // Generated by PixelShader.cpp::BuildShader() +// Declare alphakill as a variable (avoiding a constant, to allow false's to be optimized away) : +#ifndef ALPHAKILL + #define ALPHAKILL {false, false, false, false} +#endif +static bool alphakill[4] = ALPHAKILL; -// Actual texture sampling per stage (always uses the s sampling vector variable as input) +// Actual texture sampling per texture stage (ts), using the sampling vector (s) as input, // abstracting away the specifics of accessing above sampler declarations (usefull for future Direct3D 10+ sampler arrays) -float4 Sample2D(int st, float3 s) +float4 Sample2D(int ts, float3 s) { - float4 result = tex2D(samplers[st], s.xy); // Ignores s.z (and whatever it's set to, will be optimized away by the compiler, see [1] below) - if (alphakill[st]) + float4 result = tex2D(samplers[ts], s.xy); // Ignores s.z (and whatever it's set to, will be optimized away by the compiler, see [1] below) + if (alphakill[ts]) if (result.a == 0) discard; return result; } -float4 Sample3D(int st, float3 s) +float4 Sample3D(int ts, float3 s) { - float4 result = tex3D(samplers[st], s.xyz); - if (alphakill[st]) + float4 result = tex3D(samplers[ts], s.xyz); + if (alphakill[ts]) if (result.a == 0) discard; return result; } -float4 Sample6F(int st, float3 s) +float4 Sample6F(int ts, float3 s) { - float4 result = texCUBE(samplers[st], s.xyz); - if (alphakill[st]) + float4 result = texCUBE(samplers[ts], s.xyz); + if (alphakill[ts]) if (result.a == 0) discard; @@ -260,44 +267,44 @@ float4 Sample6F(int st, float3 s) #define t3 t[3] // Resolve a stage number via 'input texture (index) mapping' to it's corresponding output texture register (rgba?) -#define src(st) t[PS_INPUTTEXTURE_[st]] +#define src(ts) t[PS_INPUTTEXTURE_[ts]] -// Calculate the dot result for a given stage. Since any given stage is input-mapped to always be less than or equal the stage it appears in, this won't cause read-ahead issues +// Calculate the dot result for a given texture stage. Since any given stage is input-mapped to always be less than or equal the stage it appears in, this won't cause read-ahead issues // Test case: BumpDemo demo -#define CalcDot(st) PS_DOTMAPPING_ ## st(src(st)); dot_[st] = dot(iT[st].xyz, dm) +#define CalcDot(ts) PS_DOTMAPPING_ ## ts(src(ts)); dot_[ts] = dot(iT[ts].xyz, dm) // Addressing operations -#define Passthru(st) float4(saturate(iT[st].xyz), 1) // Clamps input texture coordinates to the range [0..1] -#define Brdf(st) float3(t[st-2].y, t[s1-1].y, t[st-2].x - t[st-1].x) // TODO : Complete 16 bit phi/sigma retrieval from float4 texture register. Perhaps use CalcHiLo? -#define Normal2(st) float3(dot_[st-1], dot_[st], 0) // Preceding and current stage dot result. Will be input for Sample2D. -#define Normal3(st) float3(dot_[st-2], dot_[st-1], dot_[st]) // Two preceding and current stage dot result. +#define Passthru(ts) float4(saturate(iT[ts].xyz), 1) // Clamps input texture coordinates to the range [0..1] +#define Brdf(ts) float3(t[ts-2].y, t[ts-1].y, t[ts-2].x - t[ts-1].x) // TODO : Complete 16 bit phi/sigma retrieval from float4 texture register. Perhaps use CalcHiLo? +#define Normal2(ts) float3(dot_[ts-1], dot_[ts], 0) // Preceding and current stage dot result. Will be input for Sample2D. +#define Normal3(ts) float3(dot_[ts-2], dot_[ts-1], dot_[ts]) // Two preceding and current stage dot result. #define Eye float3(iT[1].w, iT[2].w, iT[3].w) // 4th (q) component of input texture coordinates 1, 2 and 3. Only used by texm3x3vspec/PS_TEXTUREMODES_DOT_RFLCT_SPEC, always at stage 3. TODO : Map iT[1/2/3] through PS_INPUTTEXTURE_[]? #define Reflect(n, e) 2 * (dot(n, e) / dot(n, n)) * n - e // https://documentation.help/directx8_c/texm3x3vspec.htm -#define BumpEnv(st) float3(iT[st].x + (BEM[st].x * src(st).r) + (BEM[st].y * src(st).g), iT[st].y + (BEM[st].z * src(st).r) + (BEM[st].w * src(st).g), 0) // Will be input for Sample2D. TODO : Compact into a regular 2x2 maxtrix multiplication. -#define LSO(st) (LUM[st].x * src(st).b) + LUM[st].y // Uses PSH_XBOX_CONSTANT_LUM .x = D3DTSS_BUMPENVLSCALE .y = D3DTSS_BUMPENVLOFFSET +#define BumpEnv(ts) float3(iT[ts].x + (BEM[ts].x * src(ts).r) + (BEM[ts].y * src(ts).g), iT[ts].y + (BEM[ts].z * src(ts).r) + (BEM[ts].w * src(ts).g), 0) // Will be input for Sample2D. TODO : Compact into a regular 2x2 maxtrix multiplication. +#define LSO(ts) (LUM[ts].x * src(ts).b) + LUM[ts].y // Uses PSH_XBOX_CONSTANT_LUM .x = D3DTSS_BUMPENVLSCALE .y = D3DTSS_BUMPENVLOFFSET // Implementations for all possible texture modes, with stage as argument (prefixed with valid stages and corresponding pixel shader 1.3 assembly texture addressing instructions) // For ease of understanding, all follow this plan : Optional specifics, or dot calculation (some with normal selection) and sampling vector determination. All end by deriving a value and assigning this to the stage's texture register. -/*0123 tex */ #define PS_TEXTUREMODES_NONE(st) v = black; t[st] = v // Seems to work -/*0123 tex */ #define PS_TEXTUREMODES_PROJECT2D(st) s = iT[st].xyz; v = Sample2D(st, s); t[st] = v // Seems to work (are x/w and y/w implicit?) [1] -/*0123 tex */ #define PS_TEXTUREMODES_PROJECT3D(st) s = iT[st].xyz; v = Sample3D(st, s); t[st] = v // Seems to work (is z/w implicit?) -/*0123 tex */ #define PS_TEXTUREMODES_CUBEMAP(st) s = iT[st].xyz; v = Sample6F(st, s); t[st] = v // TODO : Test -/*0123 texcoord */ #define PS_TEXTUREMODES_PASSTHRU(st) v = Passthru(st); t[st] = v // Seems to work -/*0123 texkill */ #define PS_TEXTUREMODES_CLIPPLANE(st) PS_COMPAREMODE_ ## st(iT[st]); v = black; t[st] = v // Seems to work (setting black to texture register, in case it gets read) -/*-123 texbem */ #define PS_TEXTUREMODES_BUMPENVMAP(st) s = BumpEnv(st); v = Sample2D(st, s); t[st] = v // Seems to work -/*-123 texbeml */ #define PS_TEXTUREMODES_BUMPENVMAP_LUM(st) PS_TEXTUREMODES_BUMPENVMAP(st); v.rgb *= LSO(st); t[st] = v // TODO : Test -/*--23 texbrdf */ #define PS_TEXTUREMODES_BRDF(st) s = Brdf(st); v = Sample3D(st, s); t[st] = v // TODO : Test (t[st-2] is 16 bit eyePhi,eyeSigma; t[st-1] is lightPhi,lightSigma) -/*--23 texm3x2tex */ #define PS_TEXTUREMODES_DOT_ST(st) CalcDot(st); n = Normal2(st); s = n; v = Sample2D(st, s); t[st] = v // TODO : Test -/*--23 texm3x2depth */ #define PS_TEXTUREMODES_DOT_ZW(st) CalcDot(st); n = Normal2(st); if (n.y==0) v=1;else v = n.x / n.y; t[st] = v // TODO : Make depth-check use result of division, but how? -/*--2- texm3x3diff */ #define PS_TEXTUREMODES_DOT_RFLCT_DIFF(st) CalcDot(st); n = Normal3(st); s = n; v = Sample6F(st, s); t[st] = v // TODO : Test -/*---3 texm3x3vspec */ #define PS_TEXTUREMODES_DOT_RFLCT_SPEC(st) CalcDot(st); n = Normal3(st); s = Reflect(n, Eye); v = Sample6F(st, s); t[st] = v // TODO : Test -/*---3 texm3x3tex */ #define PS_TEXTUREMODES_DOT_STR_3D(st) CalcDot(st); n = Normal3(st); s = n; v = Sample3D(st, s); t[st] = v // TODO : Test -/*---3 texm3x3tex */ #define PS_TEXTUREMODES_DOT_STR_CUBE(st) CalcDot(st); n = Normal3(st); s = n; v = Sample6F(st, s); t[st] = v // TODO : Test -/*-123 texreg2ar */ #define PS_TEXTUREMODES_DPNDNT_AR(st) s = src(st).arg; v = Sample2D(st, s); t[st] = v // TODO : Test [1] -/*-123 texreg2bg */ #define PS_TEXTUREMODES_DPNDNT_GB(st) s = src(st).gba; v = Sample2D(st, s); t[st] = v // TODO : Test [1] -// TODO replace dm with dot_[st]? Confirm BumpDemo 'Cubemap only' modes -/*-12- texm3x2pad */ #define PS_TEXTUREMODES_DOTPRODUCT(st) CalcDot(st); v = float4(dm, 0); t[st] = v // TODO : Test all dot mapping (setting texture register, in case it gets read - test-case : BumpDemo) -/*---3 texm3x3spec */ #define PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST(st) CalcDot(st); n = Normal3(st); s = Reflect(n, c0); v = Sample6F(st, s); t[st] = v // TODO : Test +/*0123 tex */ #define PS_TEXTUREMODES_NONE(ts) v = black; t[ts] = v // Seems to work +/*0123 tex */ #define PS_TEXTUREMODES_PROJECT2D(ts) s = iT[ts].xyz; v = Sample2D(ts, s); t[ts] = v // Seems to work (are x/w and y/w implicit?) [1] +/*0123 tex */ #define PS_TEXTUREMODES_PROJECT3D(ts) s = iT[ts].xyz; v = Sample3D(ts, s); t[ts] = v // Seems to work (is z/w implicit?) +/*0123 tex */ #define PS_TEXTUREMODES_CUBEMAP(ts) s = iT[ts].xyz; v = Sample6F(ts, s); t[ts] = v // TODO : Test +/*0123 texcoord */ #define PS_TEXTUREMODES_PASSTHRU(ts) v = Passthru(ts); t[ts] = v // Seems to work +/*0123 texkill */ #define PS_TEXTUREMODES_CLIPPLANE(ts) PS_COMPAREMODE_ ## ts(iT[ts]); v = black; t[ts] = v // Seems to work (setting black to texture register, in case it gets read) +/*-123 texbem */ #define PS_TEXTUREMODES_BUMPENVMAP(ts) s = BumpEnv(ts); v = Sample2D(ts, s); t[ts] = v // Seems to work +/*-123 texbeml */ #define PS_TEXTUREMODES_BUMPENVMAP_LUM(ts) PS_TEXTUREMODES_BUMPENVMAP(ts); v.rgb *= LSO(ts); t[ts] = v // TODO : Test +/*--23 texbrdf */ #define PS_TEXTUREMODES_BRDF(ts) s = Brdf(ts); v = Sample3D(ts, s); t[ts] = v // TODO : Test (t[ts-2] is 16 bit eyePhi,eyeSigma; t[ts-1] is lightPhi,lightSigma) +/*--23 texm3x2tex */ #define PS_TEXTUREMODES_DOT_ST(ts) CalcDot(ts); n = Normal2(ts); s = n; v = Sample2D(ts, s); t[ts] = v // TODO : Test +/*--23 texm3x2depth */ #define PS_TEXTUREMODES_DOT_ZW(ts) CalcDot(ts); n = Normal2(ts); if (n.y==0) v=1;else v = n.x / n.y; t[ts] = v // TODO : Make depth-check use result of division, but how? +/*--2- texm3x3diff */ #define PS_TEXTUREMODES_DOT_RFLCT_DIFF(ts) CalcDot(ts); n = Normal3(ts); s = n; v = Sample6F(ts, s); t[ts] = v // TODO : Test +/*---3 texm3x3vspec */ #define PS_TEXTUREMODES_DOT_RFLCT_SPEC(ts) CalcDot(ts); n = Normal3(ts); s = Reflect(n, Eye); v = Sample6F(ts, s); t[ts] = v // TODO : Test +/*---3 texm3x3tex */ #define PS_TEXTUREMODES_DOT_STR_3D(ts) CalcDot(ts); n = Normal3(ts); s = n; v = Sample3D(ts, s); t[ts] = v // TODO : Test +/*---3 texm3x3tex */ #define PS_TEXTUREMODES_DOT_STR_CUBE(ts) CalcDot(ts); n = Normal3(ts); s = n; v = Sample6F(ts, s); t[ts] = v // TODO : Test +/*-123 texreg2ar */ #define PS_TEXTUREMODES_DPNDNT_AR(ts) s = src(ts).arg; v = Sample2D(ts, s); t[ts] = v // TODO : Test [1] +/*-123 texreg2bg */ #define PS_TEXTUREMODES_DPNDNT_GB(ts) s = src(ts).gba; v = Sample2D(ts, s); t[ts] = v // TODO : Test [1] +// TODO replace dm with dot_[ts]? Confirm BumpDemo 'Cubemap only' modes +/*-12- texm3x2pad */ #define PS_TEXTUREMODES_DOTPRODUCT(ts) CalcDot(ts); v = float4(dm, 0); t[ts] = v // TODO : Test all dot mapping (setting texture register, in case it gets read - test-case : BumpDemo) +/*---3 texm3x3spec */ #define PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST(ts) CalcDot(ts); n = Normal3(ts); s = Reflect(n, C0); v = Sample6F(ts, s); t[ts] = v // TODO : Test // [1] Note : 3rd component set to s.z is just an (ignored) placeholder to produce a float3 (made unique, to avoid the potential complexity of repeated components) PS_OUTPUT main(const PS_INPUT xIn) @@ -318,7 +325,7 @@ PS_OUTPUT main(const PS_INPUT xIn) float4 sum, prod; // Special purpose registers for xfc (final combiner) operation // Helper variables - int stage; // Write-only variable, generated prefixing each 'opcode', for use in C0 and C1 macro's (and should thus get optimized away) + int stage = 0; // Write-only variable, emitted as prefix-comment before each 'opcode', used in C0 and C1 macro's (and should thus get optimized away), initialized to zero for use of C0 in PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST float4 tmp; float H, L; // HILO (high/low) temps float dot_[4]; diff --git a/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsl b/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsl index bc676711a..fbe40b1e0 100644 --- a/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsl +++ b/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsl @@ -183,6 +183,12 @@ TextureArgs ExecuteTextureStage( else if (type == SAMPLE_CUBE) t = texCUBE(samplers[i], TexCoords[i].xyz + offset.xyz); +#ifdef ENABLE_FF_ALPHAKILL + if (stage.ALPHAKILL) + if (t.a == 0) + discard; + +#endif // Assign the final value for TEXTURE ctx.TEXTURE = t * factor; diff --git a/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsli b/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsli index 79c432a60..f2458947c 100644 --- a/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsli +++ b/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsli @@ -87,7 +87,11 @@ namespace FixedFunctionPixelShader { alignas(16) float COLORKEYOP; // Unimplemented Xbox extension! alignas(16) float COLORSIGN; // Unimplemented Xbox extension! +#ifdef ENABLE_FF_ALPHAKILL + alignas(16) float ALPHAKILL; // Xbox extension! +#else alignas(16) float ALPHAKILL; // Unimplemented Xbox extension! +#endif // TEXTURETRANSFORMFLAGS handled by the VS alignas(16) float BUMPENVMAT00; alignas(16) float BUMPENVMAT01; diff --git a/src/core/hle/D3D8/Direct3D9/PixelShader.cpp b/src/core/hle/D3D8/Direct3D9/PixelShader.cpp index 594f77255..384780a70 100644 --- a/src/core/hle/D3D8/Direct3D9/PixelShader.cpp +++ b/src/core/hle/D3D8/Direct3D9/PixelShader.cpp @@ -191,7 +191,7 @@ void CombinerStageHlsl(std::stringstream& hlsl, RPSCombinerStageChannel& stage, "d_bd2" // y = (x - 0.5) / 2 // PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTRIGHT_1_BIAS= 0x38L // Subtracts 0.5 from outputs and divides by 2 }; - std::string output_modifier = output_modifier_str[(stage.CombinerOutputMapping & 0x38) >> 3]; + std::string output_modifier = output_modifier_str[stage.CombinerOutputMapping >> 3]; // Concatenate it all together into an opcode 'call' (which resolves into macro expressions) hlsl << opcode_comment[opcode][0] << '(' << arguments.str() << ' ' << output_modifier; @@ -296,11 +296,11 @@ void BuildShader(DecodedRegisterCombiner* pShader, std::stringstream& hlsl) hlsl << hlsl_template[0]; // Start with the HLSL template header - hlsl << "\nstatic bool alphakill[4] = {" + hlsl << "\n#define ALPHAKILL {" << (pShader->AlphaKill[0] ? "true, " : "false, ") << (pShader->AlphaKill[1] ? "true, " : "false, ") << (pShader->AlphaKill[2] ? "true, " : "false, ") - << (pShader->AlphaKill[3] ? "true};" : "false};"); + << (pShader->AlphaKill[3] ? "true}" : "false}"); hlsl << "\n#define PS_COMBINERCOUNT " << pShader->NumberOfCombiners; if (pShader->NumberOfCombiners > 0) { diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index 204c1f8ca..bd38db034 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -102,9 +102,9 @@ extern XboxTextureStateConverter XboxTextureStates; // Declared in Direct3D9.cpp void RPSRegisterObject::Decode(uint8_t Value) { - Reg = (PS_REGISTER)(Value & PS_REGISTER_EF_PROD); // = mask = 0x0f + Reg = (PS_REGISTER)(Value & PS_REGISTER_MASK); // = 0x0f - // Validate correctness + // Validate correctness (see NOTE below) if (Reg == 6) LOG_TEST_CASE("Unknown PS_REGISTER : 6"); if (Reg == 7) LOG_TEST_CASE("Unknown PS_REGISTER : 7"); } @@ -115,8 +115,8 @@ void RPSInputRegister::Decode(uint8_t Value, unsigned stage_nr, bool isRGB) { RPSRegisterObject::Decode(Value); - Channel = (PS_CHANNEL)(Value & PS_CHANNEL_ALPHA); // = mask = 0x10 - InputMapping = (PS_INPUTMAPPING)(Value & PS_INPUTMAPPING_SIGNED_NEGATE); // = mask = 0xe0 + Channel = (PS_CHANNEL)(Value & PS_CHANNEL_MASK); // = 0x10 + InputMapping = (PS_INPUTMAPPING)(Value & PS_INPUTMAPPING_MASK); // = 0xe0 if (stage_nr == 9) { // In final combiner stage, convert C0 into FC0, and C1 into FC1, to discern them as separate registers @@ -124,7 +124,7 @@ void RPSInputRegister::Decode(uint8_t Value, unsigned stage_nr, bool isRGB) if (Reg == PS_REGISTER_C1) Reg = PS_REGISTER_FC1; } - // Validate correctness + // Validate correctness (see NOTE below) if (stage_nr <= xbox::X_PSH_COMBINECOUNT) { if (Reg == PS_REGISTER_FOG) { if (!isRGB) LOG_TEST_CASE("PS_REGISTER_FOG input not allowed in Alpha register combiner"); @@ -150,10 +150,10 @@ void RPSCombinerOutput::Decode(uint8_t Value, uint16_t PSInputs, unsigned stage_ RPSRegisterObject::Decode(Value); // Decode PSAlphaInputs / PSRGBInputs : - Input[0].Decode((PSInputs >> 8) & 0xFF, stage_nr, isRGB); - Input[1].Decode((PSInputs >> 0) & 0xFF, stage_nr, isRGB); + Input[0].Decode((uint8_t)(PSInputs >> 8), stage_nr, isRGB); + Input[1].Decode((uint8_t)(PSInputs >> 0), stage_nr, isRGB); - // Validate correctness + // Validate correctness (see NOTE below) if (Reg == PS_REGISTER_C0) LOG_TEST_CASE("PS_REGISTER_C0 not allowed as output"); if (Reg == PS_REGISTER_C1) LOG_TEST_CASE("PS_REGISTER_C1 not allowed as output"); if (Reg == PS_REGISTER_FOG) LOG_TEST_CASE("PS_REGISTER_FOG not allowed as output"); @@ -166,9 +166,9 @@ void RPSCombinerOutput::Decode(uint8_t Value, uint16_t PSInputs, unsigned stage_ void RPSCombinerStageChannel::Decode(uint32_t PSInputs, uint32_t PSOutputs, unsigned stage_nr, bool isRGB) { // Decode PSAlphaOutputs / PSRGBOutputs and PSAlphaInputs / PSRGBInputs : - OutputCD.Decode((PSOutputs >> 0) & 0xF, (PSInputs >> 0 ) & 0xFFFF, stage_nr, isRGB); - OutputAB.Decode((PSOutputs >> 4) & 0xF, (PSInputs >> 16) & 0xFFFF, stage_nr, isRGB); - OutputMUX_SUM.Decode((PSOutputs >> 8) & 0xF); + OutputCD.Decode((uint8_t)(PSOutputs >> 0), (uint16_t)(PSInputs >> 0 ), stage_nr, isRGB); + OutputAB.Decode((uint8_t)(PSOutputs >> 4), (uint16_t)(PSInputs >> 16), stage_nr, isRGB); + OutputMUX_SUM.Decode((uint8_t)(PSOutputs >> 8)); // Get the combiner output flags : PS_COMBINEROUTPUT CombinerOutputFlags = (PS_COMBINEROUTPUT)(PSOutputs >> 12); @@ -177,11 +177,11 @@ void RPSCombinerStageChannel::Decode(uint32_t PSInputs, uint32_t PSOutputs, unsi OutputCD.DotProduct = (CombinerOutputFlags & PS_COMBINEROUTPUT_CD_DOT_PRODUCT) > 0; // False=Multiply, True=DotProduct OutputAB.DotProduct = (CombinerOutputFlags & PS_COMBINEROUTPUT_AB_DOT_PRODUCT) > 0; // False=Multiply, True=DotProduct AB_CD_MUX = (CombinerOutputFlags & PS_COMBINEROUTPUT_AB_CD_MUX) > 0; // False=AB+CD, True=MUX(AB,CD) based on R0.a - CombinerOutputMapping = (PS_COMBINEROUTPUT)(CombinerOutputFlags & PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTRIGHT_1_BIAS); // = mask = 0x38 + CombinerOutputMapping = (PS_COMBINEROUTPUT_OUTPUTMAPPING)(CombinerOutputFlags & PS_COMBINEROUTPUT_OUTPUTMAPPING_MASK); // = 0x38 OutputCD.BlueToAlpha = (CombinerOutputFlags & PS_COMBINEROUTPUT_CD_BLUE_TO_ALPHA) >> 6; // 0=Alpha-to-Alpha, 1=Blue-to-Alpha OutputAB.BlueToAlpha = (CombinerOutputFlags & PS_COMBINEROUTPUT_AB_BLUE_TO_ALPHA) >> 7; // 0=Alpha-to-Alpha, 1=Blue-to-Alpha - // Discover test-cases + // Discover test-cases (see TODO below) // Check for 'discard-all-outputs' if (OutputAB.DotProduct || OutputCD.DotProduct) { if ((OutputAB.Reg == PS_REGISTER_DISCARD) && (OutputCD.Reg == PS_REGISTER_DISCARD)) LOG_TEST_CASE("All two outputs discarded"); @@ -189,7 +189,7 @@ void RPSCombinerStageChannel::Decode(uint32_t PSInputs, uint32_t PSOutputs, unsi // if ((OutputAB.Reg == PS_REGISTER_DISCARD) && (OutputCD.Reg == PS_REGISTER_DISCARD) && (OutputMUX_SUM.Reg == PS_REGISTER_DISCARD)) LOG_TEST_CASE("All three outputs discarded"); // Test-case : XDK sample : Minnaert (on Stage2.Alpha) } - // Validate correctness + // Validate correctness (see NOTE below) if ((PSOutputs & ~0x000FFFFF) > 0) LOG_TEST_CASE("Unknown PS_COMBINEROUTPUT flag bits detected"); if (CombinerOutputMapping == PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTLEFT_2_BIAS) LOG_TEST_CASE("PS_COMBINEROUTPUT_SHIFTLEFT_2_BIAS unsupported on NV2A?"); if (CombinerOutputMapping == PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTRIGHT_1_BIAS) LOG_TEST_CASE("PS_COMBINEROUTPUT_SHIFTRIGHT_1_BIAS unsupported on NV2A?"); @@ -211,27 +211,27 @@ void RPSCombinerStageChannel::Decode(uint32_t PSInputs, uint32_t PSOutputs, unsi void RPSFinalCombiner::Decode(const uint32_t PSFinalCombinerInputsABCD, const uint32_t PSFinalCombinerInputsEFG) { - Input[0].Decode((PSFinalCombinerInputsABCD >> 24) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[1].Decode((PSFinalCombinerInputsABCD >> 16) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[2].Decode((PSFinalCombinerInputsABCD >> 8) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[3].Decode((PSFinalCombinerInputsABCD >> 0) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[4].Decode((PSFinalCombinerInputsEFG >> 24) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[5].Decode((PSFinalCombinerInputsEFG >> 16) & 0xFF, /*stage_nr=*/9, /*isRGB=*/true); - Input[6].Decode((PSFinalCombinerInputsEFG >> 8) & 0xFF, /*stage_nr=*/9, /*isRGB=*/false); // Note : Final combiner input G must be a single component, and must thus be decoded as Alpha + Input[0].Decode((uint8_t)(PSFinalCombinerInputsABCD >> 24), /*stage_nr=*/9, /*isRGB=*/true); + Input[1].Decode((uint8_t)(PSFinalCombinerInputsABCD >> 16), /*stage_nr=*/9, /*isRGB=*/true); + Input[2].Decode((uint8_t)(PSFinalCombinerInputsABCD >> 8), /*stage_nr=*/9, /*isRGB=*/true); + Input[3].Decode((uint8_t)(PSFinalCombinerInputsABCD >> 0), /*stage_nr=*/9, /*isRGB=*/true); + Input[4].Decode((uint8_t)(PSFinalCombinerInputsEFG >> 24), /*stage_nr=*/9, /*isRGB=*/true); + Input[5].Decode((uint8_t)(PSFinalCombinerInputsEFG >> 16), /*stage_nr=*/9, /*isRGB=*/true); + Input[6].Decode((uint8_t)(PSFinalCombinerInputsEFG >> 8), /*stage_nr=*/9, /*isRGB=*/false); // Note : Final combiner input G must be a single component, and must thus be decoded as Alpha PS_FINALCOMBINERSETTING FinalCombinerSettingFlags = (PS_FINALCOMBINERSETTING)((PSFinalCombinerInputsEFG >> 0) & 0xFF); - ComplementV1 = FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_COMPLEMENT_V1; - ComplementR0 = FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_COMPLEMENT_R0; - ClampSum = FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_CLAMP_SUM; + ComplementV1 = (FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_COMPLEMENT_V1) > 0; + ComplementR0 = (FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_COMPLEMENT_R0) > 0; + ClampSum = (FinalCombinerSettingFlags & PS_FINALCOMBINERSETTING_CLAMP_SUM) > 0; - // Discover test-cases + // Discover test-cases (see TODO below) // if (Input[0].Channel != PS_CHANNEL_ALPHA) LOG_TEST_CASE("PS_CHANNEL_RGB/PS_CHANNEL_BLUE detected on final combiner A input"); // Note : test-case ModifyPixelShader uses PS_REGISTER_FOG.rgb and seems to expect .rgb handling (not PS_CHANNEL_BLUE's .b) if (Input[4].Channel == PS_CHANNEL_ALPHA) LOG_TEST_CASE("PS_CHANNEL_ALPHA detected on final combiner E input"); // Need test-case to determine how this should behave (calculating EF_PROD) : .aaa instead of .rgb? if (Input[5].Channel == PS_CHANNEL_ALPHA) LOG_TEST_CASE("PS_CHANNEL_ALPHA detected on final combiner F input"); // Need test-case to determine how this should behave (calculating EF_PROD) : .aaa instead of .rgb? // if (Input[6].Channel == PS_CHANNEL_BLUE) LOG_TEST_CASE("PS_CHANNEL_ALPHA detected on final combiner G input"); // PS_CHANNEL_BLUE (==0==PS_CHANNEL_RGB) uses G.b // if (Input[6].Channel == PS_CHANNEL_ALPHA) LOG_TEST_CASE("PS_CHANNEL_ALPHA detected on final combiner G input"); // PS_CHANNEL_ALPHA (==1) uses .a Test-case : XDK samples BumpDemo,BumpEarth,BumpLens,Explosion - // Validate correctness + // Validate correctness (see NOTE below) if ((FinalCombinerSettingFlags & ~0xE0) > 0) LOG_TEST_CASE("Unknown FinalCombinerSetting bits detected"); } @@ -240,9 +240,9 @@ void RPSFinalCombiner::Decode(const uint32_t PSFinalCombinerInputsABCD, const ui void DecodedRegisterCombiner::GetPSTextureModes(xbox::X_D3DPIXELSHADERDEF* pPSDef, PS_TEXTUREMODES psTextureModes[xbox::X_D3DTS_STAGECOUNT]) { for (int i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) { - psTextureModes[i] = (PS_TEXTUREMODES)((pPSDef->PSTextureModes >> (i * 5)) & 0x1F); + psTextureModes[i] = (PS_TEXTUREMODES)((pPSDef->PSTextureModes >> (i * 5)) & PS_TEXTUREMODES_MASK); - // Discover test-cases + // Discover test-cases (see TODO below) // if (psTextureModes[i] == PS_TEXTUREMODES_NONE) LOG_TEST_CASE("PS_TEXTUREMODES_NONE"); // if (psTextureModes[i] == PS_TEXTUREMODES_PROJECT2D) LOG_TEST_CASE("PS_TEXTUREMODES_PROJECT2D"); if (psTextureModes[i] == PS_TEXTUREMODES_PROJECT3D) LOG_TEST_CASE("PS_TEXTUREMODES_PROJECT3D"); // Test-case: XDK sample TechCertGame,NoSortAlphaBlend,VolumeLight @@ -263,7 +263,7 @@ void DecodedRegisterCombiner::GetPSTextureModes(xbox::X_D3DPIXELSHADERDEF* pPSDe if (psTextureModes[i] == PS_TEXTUREMODES_DOTPRODUCT) LOG_TEST_CASE("PS_TEXTUREMODES_DOTPRODUCT"); if (psTextureModes[i] == PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST) LOG_TEST_CASE("PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST"); - // Validate correctness + // Validate correctness (see NOTE below) if (psTextureModes[i] == PS_TEXTUREMODES_BUMPENVMAP) if (i < 1) LOG_TEST_CASE("PS_TEXTUREMODES_BUMPENVMAP only allowed in stage 1, 2 or 3"); if (psTextureModes[i] == PS_TEXTUREMODES_BUMPENVMAP_LUM) if (i < 1) LOG_TEST_CASE("PS_TEXTUREMODES_BUMPENVMAP_LUM only allowed in stage 1, 2 or 3"); if (psTextureModes[i] == PS_TEXTUREMODES_BRDF) if (i < 2) LOG_TEST_CASE("PS_TEXTUREMODES_BRDF only allowed in stage 2 or 3"); @@ -286,7 +286,7 @@ void DecodedRegisterCombiner::GetPSTextureModes(xbox::X_D3DPIXELSHADERDEF* pPSDe if (psTextureModes[i] > PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST) LOG_TEST_CASE("Invalid PS_TEXTUREMODES in stage?"); } - // Validate correctness + // Validate correctness (see NOTE below) if ((pPSDef->PSTextureModes & ~0x000FFFFF) > 0) LOG_TEST_CASE("Unknown PSTextureModes bits detected"); } @@ -294,9 +294,9 @@ void DecodedRegisterCombiner::GetPSDotMapping(xbox::X_D3DPIXELSHADERDEF* pPSDef, { psDotMapping[0] = (PS_DOTMAPPING)(0); for (int i = 1; i < xbox::X_D3DTS_STAGECOUNT; i++) { - psDotMapping[i] = (PS_DOTMAPPING)((pPSDef->PSDotMapping >> ((i - 1) * 4)) & 0x7); + psDotMapping[i] = (PS_DOTMAPPING)((pPSDef->PSDotMapping >> ((i - 1) * 4)) & PS_DOTMAPPING_MASK); - // Discover test-cases + // Discover test-cases (see TODO below) // if (psDotMapping[i] == PS_DOTMAPPING_ZERO_TO_ONE) LOG_TEST_CASE("PS_DOTMAPPING_ZERO_TO_ONE"); // Note : Most common scenario, no need for test-cases if (psDotMapping[i] == PS_DOTMAPPING_MINUS1_TO_1_D3D) LOG_TEST_CASE("PS_DOTMAPPING_MINUS1_TO_1_D3D"); // Test-case : XDK samples BumpDemo, Minnaert if (psDotMapping[i] == PS_DOTMAPPING_MINUS1_TO_1_GL) LOG_TEST_CASE("PS_DOTMAPPING_MINUS1_TO_1_GL"); @@ -307,22 +307,22 @@ void DecodedRegisterCombiner::GetPSDotMapping(xbox::X_D3DPIXELSHADERDEF* pPSDef, if (psDotMapping[i] == PS_DOTMAPPING_HILO_HEMISPHERE) LOG_TEST_CASE("PS_DOTMAPPING_HILO_HEMISPHERE"); } - // Validate correctness - if ((pPSDef->PSDotMapping & ~0x00000777) > 0) LOG_TEST_CASE("Unknown PSDotMapping bits detected"); + // Validate correctness (see NOTE below) + if ((pPSDef->PSDotMapping & ~0x00000777) > 0) LOG_TEST_CASE("Unknown PSDotMapping bits detected"); } void DecodedRegisterCombiner::GetPSCompareModes(xbox::X_D3DPIXELSHADERDEF* pPSDef, bool psCompareModes[xbox::X_D3DTS_STAGECOUNT][4]) { for (int i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) { - uint32_t CompareMode = (pPSDef->PSCompareMode >> (i * 4)) & 0xF; + uint32_t CompareMode = (pPSDef->PSCompareMode >> (i * 4)) & PS_COMPAREMODE_MASK; psCompareModes[i][0] = (CompareMode & PS_COMPAREMODE_S_GE) > 0; psCompareModes[i][1] = (CompareMode & PS_COMPAREMODE_T_GE) > 0; psCompareModes[i][2] = (CompareMode & PS_COMPAREMODE_R_GE) > 0; psCompareModes[i][3] = (CompareMode & PS_COMPAREMODE_Q_GE) > 0; } - // Validate correctness - if ((pPSDef->PSCompareMode & ~0x0000FFFF) > 0) LOG_TEST_CASE("Unknown PSCompareMode bits detected"); + // Validate correctness (see NOTE below) + if ((pPSDef->PSCompareMode & ~0x0000FFFF) > 0) LOG_TEST_CASE("Unknown PSCompareMode bits detected"); } void DecodedRegisterCombiner::GetPSInputTexture(xbox::X_D3DPIXELSHADERDEF* pPSDef, int psInputTexture[xbox::X_D3DTS_STAGECOUNT]) @@ -332,21 +332,22 @@ void DecodedRegisterCombiner::GetPSInputTexture(xbox::X_D3DPIXELSHADERDEF* pPSDe psInputTexture[2] = (pPSDef->PSInputTexture >> 16) & 0x1; // Stage 2 can use stage 0 or 1 psInputTexture[3] = (pPSDef->PSInputTexture >> 20) & 0x3; // Stage 3 can only use stage 0, 1 or 2 - // Discover test-cases + // Discover test-cases (see TODO below) + if (psInputTexture[2] == 0) LOG_TEST_CASE("PS_INPUTTEXTURE(2) uses texture 0"); // if (psInputTexture[2] == 1) LOG_TEST_CASE("PS_INPUTTEXTURE(2) uses texture 1"); // Test-case : XDK sample BumpEarth,Explosion,ZSprite - if (psInputTexture[2] == 2) LOG_TEST_CASE("PS_INPUTTEXTURE(2) uses texture 2"); + if (psInputTexture[3] == 0) LOG_TEST_CASE("PS_INPUTTEXTURE(3) uses texture 0"); // if (psInputTexture[3] == 1) LOG_TEST_CASE("PS_INPUTTEXTURE(3) uses texture 1"); // Test-case : XDK sample Explosion,ZSprite if (psInputTexture[3] == 2) LOG_TEST_CASE("PS_INPUTTEXTURE(3) uses texture 2"); - if (psInputTexture[3] == 3) LOG_TEST_CASE("PS_INPUTTEXTURE(3) uses texture 3"); - // Validate correctness - if ((pPSDef->PSInputTexture & ~0x00310000) > 0) LOG_TEST_CASE("Unknown PSInputTexture bits detected"); + // Validate correctness (see NOTE below) + if (psInputTexture[3] == 3) LOG_TEST_CASE("PS_INPUTTEXTURE(3) incorrectly uses texture 3"); + if ((pPSDef->PSInputTexture & ~0x00310000) > 0) LOG_TEST_CASE("Unknown PSInputTexture bits detected"); } void DecodedRegisterCombiner::Decode(xbox::X_D3DPIXELSHADERDEF *pPSDef) { NumberOfCombiners = (pPSDef->PSCombinerCount >> 0) & 0xF; - uint32_t CombinerCountFlags = (pPSDef->PSCombinerCount >> 8); + uint32_t CombinerCountFlags = (pPSDef->PSCombinerCount >> 8); // = PS_COMBINERCOUNTFLAGS CombinerMuxesOnMsb = (CombinerCountFlags & PS_COMBINERCOUNT_MUX_MSB) > 0; CombinerHasUniqueC0 = (CombinerCountFlags & PS_COMBINERCOUNT_UNIQUE_C0) > 0; @@ -368,18 +369,21 @@ void DecodedRegisterCombiner::Decode(xbox::X_D3DPIXELSHADERDEF *pPSDef) FinalCombiner.Decode(pPSDef->PSFinalCombinerInputsABCD, pPSDef->PSFinalCombinerInputsEFG); } - TexModeAdjust = (pPSDef->PSFinalCombinerConstants >> 8) & PS_GLOBALFLAGS_TEXMODE_ADJUST; + TexModeAdjust = ((pPSDef->PSFinalCombinerConstants >> PS_GLOBALFLAGS_SHIFT) & PS_GLOBALFLAGS_TEXMODE_ADJUST) > 0; - // Discover test-cases + // Discover test-cases (see TODO below) if (NumberOfCombiners == 0) LOG_TEST_CASE("NumberOfCombiners is zero"); if (!CombinerMuxesOnMsb) LOG_TEST_CASE("PS_COMBINERCOUNT_MUX_LSB detected"); // Test case required for how to implement the FCS_MUX check on LSB (see PS_COMBINERCOUNT_MUX_LSB in CxbxPixelShaderTemplate.hlsl) Note : test-case ModifyPixelShader hits this by mistake if (TexModeAdjust) LOG_TEST_CASE("PS_GLOBALFLAGS_TEXMODE_ADJUST detected"); - // Validate correctness + // Validate correctness (see NOTE below) if (NumberOfCombiners > 8) LOG_TEST_CASE("NumberOfCombiners bigger than maximum (of 8)"); if ((pPSDef->PSCombinerCount & ~0x0001110F) > 0) LOG_TEST_CASE("Unknown PSCombinerCount bits detected"); } +// * TODO : For all "Discover test-cases" LOG_TEST_CASE's that lack sufficient test-case mentions, find some, note them in an EOL comment, and comment out the entire check. +// * NOTE : For all "Validate correctness" LOG_TEST_CASE's that ever get hit, investigate what caused it, what should be done, implement that, and update the verification. + /* PSH_RECOMPILED_SHADER */ typedef struct s_CxbxPSDef { @@ -466,7 +470,7 @@ typedef struct s_CxbxPSDef { } // Pre-decode TexModeAdjust, which impacts AdjustTextureModes - DecodedTexModeAdjust = (PSDef.PSFinalCombinerConstants >> 8) & PS_GLOBALFLAGS_TEXMODE_ADJUST; + DecodedTexModeAdjust = ((PSDef.PSFinalCombinerConstants >> PS_GLOBALFLAGS_SHIFT) & PS_GLOBALFLAGS_TEXMODE_ADJUST) > 0; // Pre-decode hasFinalCombiner, which impacts AdjustFinalCombiner DecodedHasFinalCombiner = (PSDef.PSFinalCombinerInputsABCD > 0) || (PSDef.PSFinalCombinerInputsEFG > 0); @@ -669,7 +673,11 @@ std::string GetFixedFunctionShaderTemplate() { std::string_view GetD3DTOPString(int d3dtop) { static constexpr std::string_view opToString[] = { +#ifdef ENABLE_FF_ALPHAKILL + "X_D3DTOP_DISABLE", // 0 (Was UNDEFINED, but that doesn't compile) +#else "UNDEFINED", // 0 +#endif "X_D3DTOP_DISABLE", // 1 "X_D3DTOP_SELECTARG1", // 2 "X_D3DTOP_SELECTARG2", // 3 @@ -698,7 +706,11 @@ std::string_view GetD3DTOPString(int d3dtop) { "X_D3DTOP_BUMPENVMAPLUMINANCE", // 26 }; +#ifdef ENABLE_FF_ALPHAKILL + if (d3dtop < 0 || d3dtop > 26) { +#else if (d3dtop < 1 || d3dtop > 26) { +#endif EmuLog(LOG_LEVEL::ERROR2, "Unmapped texture operation %d", d3dtop); d3dtop = 0; // undefined } @@ -872,11 +884,16 @@ IDirect3DPixelShader9* GetFixedFunctionShader() stageSetup << '\n'; for (int i = 0; i < 4; i++) { +#ifdef ENABLE_FF_ALPHAKILL + // Even when a stage is disabled, we still have to fully initialize it's values, to prevent + // "error X4000: variable 'stages' used without having been completely initialized" +#else // The stage is initialized to be disabled // We don't have to output anything if (states[i].COLOROP == X_D3DTOP_DISABLE) continue; +#endif std::string target = "stages[" + std::to_string(i) + "]."; auto s = states[i]; @@ -1111,8 +1128,8 @@ void DxbxUpdateActivePixelShader() // NOPATCH LOG_TEST_CASE("Two sided lighting"); // VFACE is positive for clockwise faces // If Xbox designates counter-clockwise as front-facing, we invert VFACE - auto cwFrontface = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FRONTFACE) == 0x900; // clockwise; - frontfaceFactor = cwFrontface ? 1 : -1; + auto cwFrontface = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FRONTFACE) == 0x900; // clockwise; = NV097_SET_FRONT_FACE_V_CW = NV2A_FRONT_FACE_CW + frontfaceFactor = cwFrontface ? 1.0 : -1.0; } fColor[PSH_XBOX_CONSTANT_FRONTFACE_FACTOR].r = frontfaceFactor; diff --git a/src/core/hle/D3D8/XbPixelShader.h b/src/core/hle/D3D8/XbPixelShader.h index 49e812259..737ba9da1 100644 --- a/src/core/hle/D3D8/XbPixelShader.h +++ b/src/core/hle/D3D8/XbPixelShader.h @@ -107,6 +107,8 @@ enum PS_TEXTUREMODES PS_TEXTUREMODES_DOTPRODUCT= 0x11L, // - * * - PSInputTexture PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST= 0x12L, // - - - * Sample, PSInputTexture, PSDotMapping // 0x13-0x1f reserved + + PS_TEXTUREMODES_MASK= 0x1fL }; // ========================================================================================================= @@ -137,6 +139,8 @@ enum PS_DOTMAPPING PS_DOTMAPPING_HILO_HEMISPHERE_D3D= 0x05L, // - * * * PS_DOTMAPPING_HILO_HEMISPHERE_GL= 0x06L, // - * * * PS_DOTMAPPING_HILO_HEMISPHERE= 0x07L, // - * * * + + PS_DOTMAPPING_MASK= 0x07L }; // ========================================================================================================= @@ -161,6 +165,8 @@ enum PS_COMPAREMODE PS_COMPAREMODE_Q_LT= 0x00L, PS_COMPAREMODE_Q_GE= 0x08L, + + PS_COMPAREMODE_MASK= 0x0fL }; // ========================================================================================================= @@ -284,6 +290,8 @@ enum PS_INPUTMAPPING PS_INPUTMAPPING_HALFBIAS_NEGATE= 0xa0L, // 1/2 - max(0,x) = -1*max(0,x) + 0.5 invalid for final combiner PS_INPUTMAPPING_SIGNED_IDENTITY= 0xc0L, // x = 1* x + 0.0 invalid for final combiner PS_INPUTMAPPING_SIGNED_NEGATE= 0xe0L, // -x = -1* x + 0.0 invalid for final combiner + + PS_INPUTMAPPING_MASK= 0xe0L }; enum PS_REGISTER @@ -304,6 +312,8 @@ enum PS_REGISTER PS_REGISTER_V1R0_SUM= 0x0eL, // r A.k.a. _REG_SPECLIT PS_REGISTER_EF_PROD= 0x0fL, // r A.k.a. _REG_EF_PROD + PS_REGISTER_MASK= 0x0fL, + // These constant values can be represented as a combination of 0, and an input modifier // But they're not registers // PS_REGISTER_ONE= PS_REGISTER_ZERO | PS_INPUTMAPPING_UNSIGNED_INVERT, // 0x20 r OK for final combiner @@ -326,6 +336,8 @@ enum PS_CHANNEL PS_CHANNEL_RGB= 0x00, // used as RGB source PS_CHANNEL_BLUE= 0x00, // used as ALPHA source PS_CHANNEL_ALPHA= 0x10, // used as RGB or ALPHA source + + PS_CHANNEL_MASK= 0x10 }; enum PS_FINALCOMBINERSETTING @@ -362,6 +374,8 @@ enum PS_COMBINEROUTPUT_OUTPUTMAPPING PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTLEFT_2_BIAS= 0x28L, // y = (x - 0.5) * 4 Note : Cxbx inferred method; May not be supported on NV2A PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTRIGHT_1= 0x30L, // y = x / 2 PS_COMBINEROUTPUT_OUTPUTMAPPING_SHIFTRIGHT_1_BIAS= 0x38L, // y = (x - 0.5) / 2 Note : Cxbx inferred method; May not be supported on NV2A + + PS_COMBINEROUTPUT_OUTPUTMAPPING_MASK= 0x38L }; enum PS_COMBINEROUTPUT @@ -429,6 +443,8 @@ enum PS_GLOBALFLAGS PS_GLOBALFLAGS_NO_TEXMODE_ADJUST= 0x0000L, // don't adjust texture modes PS_GLOBALFLAGS_TEXMODE_ADJUST= 0x0001L, // adjust texture modes according to set texture + + PS_GLOBALFLAGS_SHIFT= 8 }; @@ -464,7 +480,7 @@ struct RPSCombinerStageChannel { RPSCombinerOutput OutputAB; // Contains InputA and InputB (as Input1 and Input2) RPSRegisterObject OutputMUX_SUM; bool AB_CD_MUX; // False=AB+CD, True=MUX(AB,CD) based on R0.a - PS_COMBINEROUTPUT CombinerOutputMapping; + PS_COMBINEROUTPUT_OUTPUTMAPPING CombinerOutputMapping; void Decode(uint32_t PSInputs, uint32_t PSOutputs, unsigned stage_nr, bool isRGB); };