Merge pull request #2002 from PatrickvL/ps_const_simplfy

Simplfy pixel shader constant handling;
This commit is contained in:
Luke Usher 2020-10-28 13:40:57 +00:00 committed by GitHub
commit 5fe769b906
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 152 additions and 250 deletions

View File

@ -7310,7 +7310,11 @@ xbox::void_xt __declspec(noinline) D3DDevice_SetPixelShaderCommon(xbox::dword_xt
// This mirrors the fact that unpatched SetPixelShader does the same thing!
// This shouldn't be necessary anymore, but shaders still break if we don't do this
if (g_pXbox_PixelShader != nullptr) {
// TODO : If D3DDevice_SetPixelShader() in XDKs don't overwrite the X_D3DRS_PS_RESERVED slot with PSDef.PSTextureModes,
// store it here and restore after memcpy, or alternatively, perform two separate memcpy's (the halves before, and after the reserved slot).
memcpy(XboxRenderStates.GetPixelShaderRenderStatePointer(), g_pXbox_PixelShader->pPSDef, sizeof(xbox::X_D3DPIXELSHADERDEF) - 3 * sizeof(DWORD));
// Copy the PSDef.PSTextureModes field to it's dedicated slot, which lies outside the range of PixelShader render state slots
// Note : This seems to be what XDK's do as well. Needs verification.
XboxRenderStates.SetXboxRenderState(xbox::X_D3DRS_PSTEXTUREMODES, g_pXbox_PixelShader->pPSDef->PSTextureModes);
}
}
@ -8780,43 +8784,3 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_GetMaterial)
hRet = D3D_OK;
}
}
// LTCG specific D3DDevice_SetPixelShaderConstant function...
// This uses a custom calling convention where parameter is passed in ECX, EAX
// TODO: Log function is not working due lost parameter in EAX.
// Test-case: Otogi 2, Ninja Gaiden: Black
xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4)
(
CONST PVOID pConstantData
)
{
DWORD Register;
DWORD ConstantCount;
__asm {
mov Register, ecx
mov ConstantCount, eax
}
//LOG_FUNC_BEGIN
// LOG_FUNC_ARG(Register)
// LOG_FUNC_ARG(pConstantData)
// LOG_FUNC_ARG(ConstantCount)
// LOG_FUNC_END;
EmuLog(LOG_LEVEL::DEBUG, "D3DDevice_SetPixelShaderConstant_4(Register : %d pConstantData : %08X ConstantCount : %d);", Register, pConstantData, ConstantCount);
HRESULT hRet = g_pD3DDevice->SetPixelShaderConstantF
(
Register,
(PixelShaderConstantType*)pConstantData,
ConstantCount
);
//DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetPixelShaderConstant");
if(FAILED(hRet))
{
EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a pixel shader constant!");
hRet = D3D_OK;
}
}

View File

@ -4155,3 +4155,43 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_GetTransform)
HRESULT hRet = g_pD3DDevice->GetTransform(State, pMatrix);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetTransform");
}
// LTCG specific D3DDevice_SetPixelShaderConstant function...
// This uses a custom calling convention where parameter is passed in ECX, EAX
// TODO: Log function is not working due lost parameter in EAX.
// Test-case: Otogi 2, Ninja Gaiden: Black
xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4)
(
CONST PVOID pConstantData
)
{
DWORD Register;
DWORD ConstantCount;
__asm {
mov Register, ecx
mov ConstantCount, eax
}
//LOG_FUNC_BEGIN
// LOG_FUNC_ARG(Register)
// LOG_FUNC_ARG(pConstantData)
// LOG_FUNC_ARG(ConstantCount)
// LOG_FUNC_END;
EmuLog(LOG_LEVEL::DEBUG, "D3DDevice_SetPixelShaderConstant_4(Register : %d pConstantData : %08X ConstantCount : %d);", Register, pConstantData, ConstantCount);
HRESULT hRet = g_pD3DDevice->SetPixelShaderConstantF
(
Register,
(PixelShaderConstantType*)pConstantData,
ConstantCount
);
//DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetPixelShaderConstant");
if(FAILED(hRet))
{
EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a pixel shader constant!");
hRet = D3D_OK;
}
}

View File

@ -419,21 +419,6 @@ xbox::hresult_xt WINAPI EMUPATCH(D3DDevice_CreateVertexShader)
dword_xt Usage
);
// ******************************************************************
// * patch: D3DDevice_SetPixelShaderConstant
// ******************************************************************
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetPixelShaderConstant)
(
dword_xt Register,
CONST PVOID pConstantData,
dword_xt ConstantCount
);
xbox::void_xt WINAPI EMUPATCH(D3DDevice_SetPixelShaderConstant_4)
(
CONST PVOID pConstantData
);
// ******************************************************************
// * patch: D3DDevice_SetVertexShaderConstant
// ******************************************************************

View File

@ -406,7 +406,7 @@ typedef struct _X_D3DPIXELSHADERDEF // <- blueshogun 10/1/07
DWORD PSFinalCombinerConstant1; // X_D3DRS_PSFINALCOMBINERCONSTANT1 : C1 in final combiner
DWORD PSRGBOutputs[8]; // X_D3DRS_PSRGBOUTPUTS0..X_D3DRS_PSRGBOUTPUTS7 : Stage 0 RGB outputs
DWORD PSCombinerCount; // X_D3DRS_PSCOMBINERCOUNT : Active combiner count (Stages 0-7)
DWORD PSTextureModes; // X_D3DRS_PSTEXTUREMODES: Texture addressing modes
DWORD PSTextureModes; // X_D3DRS_PS_RESERVED (copied from out-of-range X_D3DRS_PSTEXTUREMODES) : Texture addressing modes
DWORD PSDotMapping; // X_D3DRS_PSDOTMAPPING : Input mapping for dot product modes
DWORD PSInputTexture; // X_D3DRS_PSINPUTTEXTURE : Texture source for some texture modes

View File

@ -627,15 +627,24 @@ constexpr int PSH_XBOX_MAX_C_REGISTER_COUNT = 16;
constexpr int PSH_XBOX_MAX_R_REGISTER_COUNT = 2;
constexpr int PSH_XBOX_MAX_T_REGISTER_COUNT = 4;
constexpr int PSH_XBOX_MAX_V_REGISTER_COUNT = 2;
// Extra constants to support features not present in Native D3D :
constexpr int PSH_XBOX_CONSTANT_FOG = PSH_XBOX_MAX_C_REGISTER_COUNT; // = 16
constexpr int PSH_XBOX_CONSTANT_FC0 = PSH_XBOX_CONSTANT_FOG + 1; // = 17
constexpr int PSH_XBOX_CONSTANT_FC1 = PSH_XBOX_CONSTANT_FC0 + 1; // = 18
constexpr int PSH_XBOX_CONSTANT_MUL0 = PSH_XBOX_CONSTANT_FC1 + 1; // = 19
constexpr int PSH_XBOX_CONSTANT_MUL1 = PSH_XBOX_CONSTANT_MUL0 + 1; // = 20
constexpr int PSH_XBOX_CONSTANT_BEM = PSH_XBOX_CONSTANT_MUL1 + 1; // = 21
constexpr int PSH_XBOX_CONSTANT_LUM = PSH_XBOX_CONSTANT_BEM + 4; // = 25
constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_LUM + 4; // = 29
// Mapping indices of Xbox register combiner constants to host pixel shader constants;
// The first 16 are identity-mapped (C0_1 .. C0_7 are C0 .. C7 on host, C1_0 .. C1_7 are C8 .. C15 on host) :
constexpr int PSH_XBOX_CONSTANT_C0 = 0; // = 0..15
// Then two final combiner constants :
constexpr int PSH_XBOX_CONSTANT_FC0 = PSH_XBOX_CONSTANT_C0 + PSH_XBOX_MAX_C_REGISTER_COUNT; // = 16
constexpr int PSH_XBOX_CONSTANT_FC1 = PSH_XBOX_CONSTANT_FC0 + 1; // = 17
// Fog requires a constant (as host PS1.4 doesn't support the FOG register)
constexpr int PSH_XBOX_CONSTANT_FOG = PSH_XBOX_CONSTANT_FC1 + 1; // = 18
// Bump Environment Material registers
constexpr int PSH_XBOX_CONSTANT_BEM = PSH_XBOX_CONSTANT_FOG + 1; // = 19..22
// Bump map Luminance registers
constexpr int PSH_XBOX_CONSTANT_LUM = PSH_XBOX_CONSTANT_BEM + 4; // = 23..26
// This concludes the set of constants that need to be set on host :
constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_LUM + 4; // = 27
// After those, we need two constants for literal values, which we DEF'ine in ConvertConstantsToNative :
constexpr int PSH_XBOX_CONSTANT_MUL0 = PSH_XBOX_CONSTANT_MAX; // = 27
constexpr int PSH_XBOX_CONSTANT_MUL1 = PSH_XBOX_CONSTANT_MUL0 + 1; // = 28
constexpr int FakeRegNr_Sum = PSH_XBOX_MAX_T_REGISTER_COUNT + 0;
constexpr int FakeRegNr_Prod = PSH_XBOX_MAX_T_REGISTER_COUNT + 1;
@ -792,8 +801,6 @@ typedef struct _PSH_RECOMPILED_SHADER {
xbox::X_D3DPIXELSHADERDEF PSDef;
std::string NewShaderStr;
DWORD ConvertedHandle;
bool ConstInUse[PSH_XBOX_CONSTANT_MAX];
int ConstMapping[PSH_XBOX_CONSTANT_MAX];
} PSH_RECOMPILED_SHADER,
*PPSH_RECOMPILED_SHADER;
@ -907,8 +914,6 @@ struct PSH_XBOX_SHADER {
void ConvertXboxOpcodesToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef);
void _SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLOR ConstColor);
void _SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLORVALUE ConstColor);
int _MapConstant(int ConstNr, bool *NativeConstInUse);
int _HandleConst(int XboxConst, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled, bool *NativeConstInUse, bool *EmittedNewConstant);
bool ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled);
bool RemoveUselessWrites();
int MaxRegisterCount(PSH_ARGUMENT_TYPE aRegType);
@ -1260,99 +1265,87 @@ bool PSH_IMD_ARGUMENT::HasModifier(PSH_ARG_MODIFIER modifier)
bool PSH_IMD_ARGUMENT::SetScaleConstRegister(float factor, const PSH_RECOMPILED_SHADER& pRecompiled)
{
bool result = false;
PSH_ARG_MODIFIERs modifiers = 0;
DWORD mask = Mask;
int address = Address;
const int mappedConstant0 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_MUL0];
const int mappedConstant1 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_MUL1];
const int mappedConstant0 = PSH_XBOX_CONSTANT_MUL0;
const int mappedConstant1 = PSH_XBOX_CONSTANT_MUL1;
if (factor < 0.0f)
{
factor = -factor;
modifiers = (1 << ARGMOD_NEGATE);
// This inversion is here to support negative scales, but it's not an actual match yet.
}
// Note : 'switch(factor)' can't be used here, since that requires an ordinal value (and factor is a float)
if (factor == 1.0f)
{
address = mappedConstant0;
mask = MASK_R;
result = true;
}
else if (factor == 2.0f)
{
address = mappedConstant0;
mask = MASK_G;
result = true;
}
else if (factor == 4.0f)
{
address = mappedConstant0;
mask = MASK_B;
result = true;
}
else if (factor == 8.0f)
{
address = mappedConstant0;
mask = MASK_A;
result = true;
}
else if (factor == 0.0f)
{
address = mappedConstant1;
mask = MASK_R;
result = true;
}
else if (factor == 1.0f / 2.0f)
{
address = mappedConstant1;
mask = MASK_G;
result = true;
}
else if (factor == 1.0f / 4.0f)
{
address = mappedConstant1;
mask = MASK_B;
result = true;
}
else if (factor == 1.0f / 8.0f)
{
address = mappedConstant1;
mask = MASK_A;
result = true;
}
else return false;
if (result)
{
Type = PARAM_C;
Address = address;
Mask = mask;
Modifiers = modifiers;
Multiplier = 1.0f;
}
return result;
return true;
}
bool PSH_IMD_ARGUMENT::SetScaleBemLumRegister(D3DTEXTURESTAGESTATETYPE factor, int stage, const PSH_RECOMPILED_SHADER& pRecompiled)
{
bool result = false;
PSH_ARG_MODIFIERs modifiers = 0;
const PSH_ARG_MODIFIERs modifiers = 0;
DWORD mask = Mask;
int address = Address;
const int mappedConstant0 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_BEM + stage];
const int mappedConstant1 = pRecompiled.ConstMapping[PSH_XBOX_CONSTANT_LUM + stage];
const int mappedConstant0 = PSH_XBOX_CONSTANT_BEM + stage;
const int mappedConstant1 = PSH_XBOX_CONSTANT_LUM + stage;
switch (factor)
{
@ -1360,56 +1353,48 @@ bool PSH_IMD_ARGUMENT::SetScaleBemLumRegister(D3DTEXTURESTAGESTATETYPE factor, i
{
address = mappedConstant0;
mask = MASK_R;
result = true;
break;
}
case D3DTSS_BUMPENVMAT01:
{
address = mappedConstant0;
mask = MASK_G;
result = true;
break;
}
case D3DTSS_BUMPENVMAT11:
{
address = mappedConstant0;
mask = MASK_B;
result = true;
break;
}
case D3DTSS_BUMPENVMAT10:
{
address = mappedConstant0;
mask = MASK_A;
result = true;
break;
}
case D3DTSS_BUMPENVLSCALE:
{
address = mappedConstant1;
mask = MASK_R;
result = true;
break;
}
case D3DTSS_BUMPENVLOFFSET:
{
address = mappedConstant1;
mask = MASK_G;
result = true;
break;
}
default: return false;
}
if (result)
{
Type = PARAM_C;
Address = address;
Mask = mask;
Modifiers = modifiers;
Multiplier = 1.0f;
}
return result;
return true;
}
std::string PSH_IMD_ARGUMENT::ToString()
@ -3396,8 +3381,6 @@ bool PSH_XBOX_SHADER::MoveRemovableParametersRight()
return Result;
} // MoveRemovableParametersRight
//bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled)
void PSH_XBOX_SHADER::_SetColor(/*var OUT*/PSH_INTERMEDIATE_FORMAT &NewIns, D3DCOLOR ConstColor)
{
D3DXCOLOR XColor;
@ -3420,90 +3403,26 @@ bool PSH_XBOX_SHADER::MoveRemovableParametersRight()
NewIns.Parameters[3].SetConstValue(ConstColor.a);
}
// Try to fixup constants above the limit (c7 for PS.1.3) :
int PSH_XBOX_SHADER::_MapConstant(int ConstNr, bool *NativeConstInUse)
{
// 1-to-1 mapping for constants that can be supported native (if not used already) :
if ((ConstNr < MaxConstantFloatRegisters) && (!NativeConstInUse[ConstNr]))
{
return ConstNr;
}
// Assign not-yet-defined constants bottom-to-up :
int Result = 0;
while (Result < MaxConstantFloatRegisters)
{
if (!NativeConstInUse[Result])
return Result;
++Result;
}
// Unresolved - fallback to 1st constant :
if (Result >= MaxConstantFloatRegisters)
Result = 0;
EmuLog(LOG_LEVEL::WARNING, "; Too many constants to emulate, this pixel shader will give unexpected output!");
return Result;
}
int PSH_XBOX_SHADER::_HandleConst(int XboxConst, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled, bool *NativeConstInUse, bool *EmittedNewConstant)
{
int NativeConst;
if (!Recompiled->ConstInUse[XboxConst])
{
// Determine and remember a new mapping to native :
NativeConst = _MapConstant(XboxConst, NativeConstInUse);
NativeConstInUse[NativeConst] = true;
Recompiled->ConstMapping[XboxConst] = NativeConst;
Recompiled->ConstInUse[XboxConst] = true;
// Make sure we can check this is a new constant (so we can emit a constant declaration
// for any final combiner constants - because those cannot be set via SetPixelShaderConstant) :
*EmittedNewConstant = true;
}
// Return the (previously) determined mapping :
return Recompiled->ConstMapping[XboxConst];
}
bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef, /*var OUT*/PSH_RECOMPILED_SHADER *Recompiled)
{
int i, j;
PPSH_INTERMEDIATE_FORMAT Cur;
PPSH_IMD_ARGUMENT CurArg;
bool NativeConstInUse[224]; // Note : 224 = highest possible MaxConstantFloatRegisters
int16_t OriginalConstantNr;
bool EmittedNewConstant = false;
PSH_INTERMEDIATE_FORMAT NewIns = {};
bool Result = false;
// Note : Recompiled.ConstMapping and Recompiled.ConstInUse[i] are still empty here.
for (i = 0; i < MaxConstantFloatRegisters; i++)
NativeConstInUse[i] = false;
Result = true;
NewIns.Initialize(PO_DEF);
// Add constants used to represent common powers of 2 used by instruction and argument modifiers
// Represent constant 0.0 and common powers of 2 divisions
NewIns.Output[0].SetRegister(PARAM_C, _HandleConst(PSH_XBOX_CONSTANT_MUL1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant), MASK_RGBA);
NewIns.Output[0].SetRegister(PARAM_C, PSH_XBOX_CONSTANT_MUL1, MASK_RGBA);
_SetColor(NewIns, { 0.0, 1.0 / 2.0, 1.0 / 4.0, 1.0 / 8.0 });
InsertIntermediate(&NewIns, 1);
// Represent common powers of 2 constants, also used as multipliers
NewIns.Output[0].SetRegister(PARAM_C, _HandleConst(PSH_XBOX_CONSTANT_MUL0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant), MASK_RGBA);
NewIns.Output[0].SetRegister(PARAM_C, PSH_XBOX_CONSTANT_MUL0, MASK_RGBA);
_SetColor(NewIns, {1.0, 2.0, 4.0, 8.0});
InsertIntermediate(&NewIns, 1);
for (i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++)
{
_HandleConst(PSH_XBOX_CONSTANT_BEM + i, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
_HandleConst(PSH_XBOX_CONSTANT_LUM + i, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
}
// Loop over all opcodes to update the constant-indexes (Xbox uses C0 and C1 in each combiner) :
for (i = 0; i < IntermediateCount; i++)
{
@ -3521,7 +3440,7 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef
if (CurArg->Mask != MASK_A)
{
CurArg->Type = PARAM_C;
CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FOG, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = PSH_XBOX_CONSTANT_FOG;
CurArg->Mask = CurArg->Mask & (!MASK_A);
}
else
@ -3539,11 +3458,6 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef
if (CurArg->Type != PARAM_C)
continue;
// Make sure we can detect new constants (and if it was C0 or C1),
// as we need this for fixing up final combiner constants :
EmittedNewConstant = false;
OriginalConstantNr = CurArg->Address;
// For each constant being addressed, we find out which Xbox constant it is,
// and map it to a native constant (as far as we have space for them) :
switch (CurArg->Address) {
@ -3551,16 +3465,16 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef
{
// The final combiner has a separate C0 constant :
if (Cur->CombinerStageNr == XFC_COMBINERSTAGENR)
CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FC0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = PSH_XBOX_CONSTANT_FC0;
else
{
// See if C0 has a unique index per combiner stage :
if (CombinerHasUniqueC0)
// C0 actually ranges from c0 to c7, one for each possible combiner stage (X_D3DRS_PSCONSTANT0_0..X_D3DRS_PSCONSTANT0_7) :
CurArg->Address = _HandleConst(Cur->CombinerStageNr, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = Cur->CombinerStageNr;
else
// Non-unique just reads the same C0 in every stage :
CurArg->Address = _HandleConst(0, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = 0;
}
break;
}
@ -3569,43 +3483,24 @@ bool PSH_XBOX_SHADER::ConvertConstantsToNative(xbox::X_D3DPIXELSHADERDEF *pPSDef
{
// The final combiner has a separate C1 constant :
if (Cur->CombinerStageNr == XFC_COMBINERSTAGENR)
CurArg->Address = _HandleConst(PSH_XBOX_CONSTANT_FC1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = PSH_XBOX_CONSTANT_FC1;
else
{
// See if C1 has a unique index per combiner stage :
if (CombinerHasUniqueC1)
// C1 actually ranges from c8 to c15, one for each possible combiner stage (X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7) :
CurArg->Address = _HandleConst(Cur->CombinerStageNr + 8, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = Cur->CombinerStageNr + 8;
else
// Non-unique just reads the same C1 in every stage :
CurArg->Address = _HandleConst(1, Recompiled, &NativeConstInUse[0], &EmittedNewConstant);
CurArg->Address = 1;
}
break;
}
} // switch
// New constants solely used for the final combiner must be DEFined separately,
// as there's no other way to set these (SetPixelShaderConstant can only write
// to the 16 slots X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7) :
if ((Cur->CombinerStageNr == XFC_COMBINERSTAGENR) && EmittedNewConstant)
{
// Output a new opcode to define this constant :
NewIns.Initialize(PO_DEF);
NewIns.Output[0].SetRegister(PARAM_C, CurArg->Address, MASK_RGBA);
if (OriginalConstantNr == 0)
_SetColor(NewIns, pPSDef->PSFinalCombinerConstant0);
else
_SetColor(NewIns, pPSDef->PSFinalCombinerConstant1);
// PO_DEF opcodes go after the initial PO_XPS (which is not yet replaced by PO_COMMENT+PO_PS,
// see ConvertXboxOpcodesToNative calling ConvertXPSToNative for that)
InsertIntermediate(&NewIns, 1);
Result = true;
}
} // for arguments
} // for opcodes
return Result;
return true;
} // ConvertConstantsToNative
bool PSH_XBOX_SHADER::RemoveUselessWrites()
@ -5234,9 +5129,7 @@ bool PSH_XBOX_SHADER::FixupPixelShader()
// TODO : Fixup the usage of non-existent register numbers (like FakeRegNr_Sum and FakeRegNr_Prod)
// TODO : Fixup the usage of the unsupported INSMOD_BIAS and INSMOD_BX2 instruction modifiers
// TODO : Use the INSMOD_SAT instruction modifier instead of the ARGMOD_SATURATE argument modifier
// TODO : Condense constants registers, to avoid the non-existant C8-C15 (requires a mapping in SetPixelShaderConstant too...)
// TODO : Convert numeric arguments (-2, -1, 0, 1, 2) into modifiers on the other argument
// TODO : Complete to port to D3D9 to support all 18 constants (including C8..C15 + FC0+FC1)
if (CombineInstructions())
Result = true;
@ -5958,6 +5851,39 @@ static const
std::vector<PSH_RECOMPILED_SHADER> g_RecompiledPixelShaders;
bool ArePSDefsIdentical(xbox::X_D3DPIXELSHADERDEF &PSDef1, xbox::X_D3DPIXELSHADERDEF &PSDef2)
{
// Only compare the [*]-marked members, which forms the unique shader declaration (ignore the constants and Xbox Direct3D8 run-time fields) :
// [*] DWORD PSAlphaInputs[8]; // X_D3DRS_PSALPHAINPUTS0..X_D3DRS_PSALPHAINPUTS7 : Alpha inputs for each stage
// [*] DWORD PSFinalCombinerInputsABCD; // X_D3DRS_PSFINALCOMBINERINPUTSABCD : Final combiner inputs
// [*] DWORD PSFinalCombinerInputsEFG; // X_D3DRS_PSFINALCOMBINERINPUTSEFG : Final combiner inputs (continued)
if (memcmp(&(PSDef1.PSAlphaInputs[0]), &(PSDef2.PSAlphaInputs[0]), (8 + 1 + 1) * sizeof(DWORD)) != 0)
return false;
// [-] DWORD PSConstant0[8]; // X_D3DRS_PSCONSTANT0_0..X_D3DRS_PSCONSTANT0_7 : C0 for each stage
// [-] DWORD PSConstant1[8]; // X_D3DRS_PSCONSTANT1_0..X_D3DRS_PSCONSTANT1_7 : C1 for each stage
// [*] DWORD PSAlphaOutputs[8]; // X_D3DRS_PSALPHAOUTPUTS0..X_D3DRS_PSALPHAOUTPUTS7 : Alpha output for each stage
// [*] DWORD PSRGBInputs[8]; // X_D3DRS_PSRGBINPUTS0..X_D3DRS_PSRGBINPUTS7 : RGB inputs for each stage
// [*] DWORD PSCompareMode; // X_D3DRS_PSCOMPAREMODE : Compare modes for clipplane texture mode
if (memcmp(&(PSDef1.PSAlphaOutputs[0]), &(PSDef2.PSAlphaOutputs[0]), (8 + 8 + 1) * sizeof(DWORD)) != 0)
return false;
// [-] DWORD PSFinalCombinerConstant0; // X_D3DRS_PSFINALCOMBINERCONSTANT0 : C0 in final combiner
// [-] DWORD PSFinalCombinerConstant1; // X_D3DRS_PSFINALCOMBINERCONSTANT1 : C1 in final combiner
// [*] DWORD PSRGBOutputs[8]; // X_D3DRS_PSRGBOUTPUTS0..X_D3DRS_PSRGBOUTPUTS7 : Stage 0 RGB outputs
// [*] DWORD PSCombinerCount; // X_D3DRS_PSCOMBINERCOUNT : Active combiner count (Stages 0-7)
// [*] DWORD PSTextureModes; // X_D3DRS_PS_RESERVED (copied from out-of-range X_D3DRS_PSTEXTUREMODES) : Texture addressing modes
// [*] DWORD PSDotMapping; // X_D3DRS_PSDOTMAPPING : Input mapping for dot product modes
// [*] DWORD PSInputTexture; // X_D3DRS_PSINPUTTEXTURE : Texture source for some texture modes
if (memcmp(&(PSDef1.PSRGBOutputs[0]), &(PSDef2.PSRGBOutputs[0]), (8 + 1 + 1 + 1 + 1) * sizeof(DWORD)) != 0)
return false;
// [-] DWORD PSC0Mapping; // Mapping of c0 regs to D3D constants
// [-] DWORD PSC1Mapping; // Mapping of c1 regs to D3D constants
// [-] DWORD PSFinalCombinerConstants; // Final combiner constant mapping
return true;
}
void DxbxUpdateActivePixelShader() // NOPATCH
{
xbox::X_D3DPIXELSHADERDEF *pPSDef;
@ -5965,9 +5891,8 @@ void DxbxUpdateActivePixelShader() // NOPATCH
DWORD ConvertedPixelShaderHandle;
DWORD CurrentPixelShader;
int i;
DWORD Register_;
D3DCOLOR dwColor;
D3DXCOLOR fColor;
D3DXCOLOR fColor[PSH_XBOX_CONSTANT_MAX];
HRESULT Result = D3D_OK;
@ -5977,32 +5902,35 @@ void DxbxUpdateActivePixelShader() // NOPATCH
// Use the pixel shader stored in D3D__RenderState rather than the set handle
// This allows changes made via SetRenderState to actually take effect!
// NOTE: PSTextureModes is in a different location in the X_D3DPIXELSHADERFEF than in Render State mappings
// NOTE: PSTextureModes is in a different location in the X_D3DPIXELSHADERDEF than in Render State mappings
// All other fields are the same.
// We cast D3D__RenderState to a pPSDef for these fields, but
// manually read from D3D__RenderState[X_D3DRS_PSTEXTUREMODES) for that one field.
// manually read from D3D__RenderState[X_D3DRS_PSTEXTUREMODES] for that one field.
// See D3DDevice_SetPixelShaderCommon which implements this
pPSDef = g_pXbox_PixelShader != nullptr ? (xbox::X_D3DPIXELSHADERDEF*)(XboxRenderStates.GetPixelShaderRenderStatePointer()) : nullptr;
if (pPSDef != nullptr)
{
// Create a copy of the pixel shader definition, as it is residing in render state register slots :
xbox::X_D3DPIXELSHADERDEF PSDefCopy = *pPSDef;
// Copy-in the PSTextureModes value which is stored outside the range of Xbox pixel shader render state slots :
PSDefCopy.PSTextureModes = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSTEXTUREMODES);
RecompiledPixelShader = nullptr;
// Now, see if we already have a shader compiled for this declaration :
// TODO : Change g_RecompiledPixelShaders into an unordered_map, hash just the identifying PSDef members, and add cache eviction (clearing host resources when pruning)
for (auto it = g_RecompiledPixelShaders.begin(); it != g_RecompiledPixelShaders.end(); ++it) {
// Only compare parts that form a unique shader (ignore the constants and Direct3D8 run-time fields) :
if ((memcmp(&(it->PSDef.PSAlphaInputs[0]), &(pPSDef->PSAlphaInputs[0]), (8 + 2) * sizeof(DWORD)) == 0)
&& (memcmp(&(it->PSDef.PSAlphaOutputs[0]), &(pPSDef->PSAlphaOutputs[0]), (8 + 8 + 3 + 8 + 4) * sizeof(DWORD)) == 0)) {
if (ArePSDefsIdentical(it->PSDef, PSDefCopy)) {
RecompiledPixelShader = &(*it);
break;
}
}
// If none was found, recompile this shader and remember it :
if (RecompiledPixelShader == nullptr) {
// Recompile this pixel shader :
g_RecompiledPixelShaders.push_back(DxbxRecompilePixelShader(pPSDef));
g_RecompiledPixelShaders.push_back(DxbxRecompilePixelShader(&PSDefCopy));
RecompiledPixelShader = &g_RecompiledPixelShaders.back();
}
@ -6014,10 +5942,6 @@ void DxbxUpdateActivePixelShader() // NOPATCH
if (CurrentPixelShader != ConvertedPixelShaderHandle)
g_pD3DDevice->SetPixelShader((IDirect3DPixelShader*)ConvertedPixelShaderHandle);
// Note : We set the constants /after/ setting the shader, so that any
// constants in the shader declaration can be overwritten (this will be
// needed for the final combiner constants at least)!
// TODO: Figure out a method to forward the vertex-shader oFog output to the pixel shader FOG input register :
// We could use the unused oT4.x to output fog from the vertex shader, and read it with 'texcoord t4' in pixel shader!
// For now, we still disable native fog if pixel shader is said to handle it, this prevents black screen issues in titles using pixel shader fog.
@ -6051,31 +5975,28 @@ void DxbxUpdateActivePixelShader() // NOPATCH
// as these could have been updated via SetRenderState or otherwise :
for (i = 0; i < PSH_XBOX_CONSTANT_MAX; i++)
{
if (RecompiledPixelShader->ConstInUse[i])
// Assume all constants are in use (this is much easier than tracking them for no other purpose than to skip a few here)
{
// Read the color from the corresponding render state slot :
switch (i) {
case PSH_XBOX_CONSTANT_FOG:
// Note : FOG.RGB is correct like this, but FOG.a should be coming
// from the vertex shader (oFog) - however, D3D8 does not forward this...
fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FOGCOLOR);
fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_FOGCOLOR);
break;
case PSH_XBOX_CONSTANT_FC0:
fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT0);
fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT0);
break;
case PSH_XBOX_CONSTANT_FC1:
fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT1);
fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSFINALCOMBINERCONSTANT1);
break;
case PSH_XBOX_CONSTANT_MUL0:
case PSH_XBOX_CONSTANT_MUL1:
continue;
case PSH_XBOX_CONSTANT_BEM + 0:
case PSH_XBOX_CONSTANT_BEM + 1:
case PSH_XBOX_CONSTANT_BEM + 2:
case PSH_XBOX_CONSTANT_BEM + 3:
{
int stage = i - PSH_XBOX_CONSTANT_BEM;
DWORD* value = (DWORD*)&fColor;
DWORD* value = (DWORD*)&fColor[i];
g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVMAT00, &value[0]);
g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVMAT01, &value[1]);
@ -6089,7 +6010,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH
case PSH_XBOX_CONSTANT_LUM + 3:
{
int stage = i - PSH_XBOX_CONSTANT_LUM;
DWORD* value = (DWORD*)&fColor;
DWORD* value = (DWORD*)&fColor[i];
g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVLSCALE, &value[0]);
g_pD3DDevice->GetTextureStageState(stage, D3DTSS_BUMPENVLOFFSET, &value[1]);
@ -6097,24 +6018,16 @@ void DxbxUpdateActivePixelShader() // NOPATCH
value[3] = 0;
break;
}
default:
fColor = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i);
default: // PSH_XBOX_CONSTANT_C0..C15 are stored as-is in (and should thus be read from) the Xbox render state pixel shader constant slots
fColor[i] = dwColor = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSCONSTANT0_0 + i - PSH_XBOX_CONSTANT_C0);
break;
}
// Convert it back to 4 floats :
//fColor = dwColor;
// Read the register we can use on PC :
Register_ = RecompiledPixelShader->ConstMapping[i];
// TODO : Avoid the following setter if it's no different from the previous update (this might speed things up)
// Set the value locally in this register :
g_pD3DDevice->SetPixelShaderConstantF
(
Register_,
(PixelShaderConstantType*)(&fColor),
1
);
}
// Set all host constant values using a single call:
g_pD3DDevice->SetPixelShaderConstantF(0, (PixelShaderConstantType*)(&fColor[0]), PSH_XBOX_CONSTANT_MAX);
// Note PSH_XBOX_CONSTANT_MUL0 and PSH_XBOX_CONSTANT_MUL1 fall outside PSH_XBOX_CONSTANT_MAX
// and have already been 'PO_DEF'ined at the start of ConvertConstantsToNative
}
}
else

View File

@ -133,7 +133,7 @@ std::map<const std::string, const xbox_patch_t> g_PatchTable = {
PATCH_ENTRY("D3DDevice_SetPalette", xbox::EMUPATCH(D3DDevice_SetPalette), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetPalette_4", xbox::EMUPATCH(D3DDevice_SetPalette_4), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetPixelShader", xbox::EMUPATCH(D3DDevice_SetPixelShader), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetPixelShaderConstant_4", xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4), PATCH_HLE_D3D),
//PATCH_ENTRY("D3DDevice_SetPixelShaderConstant_4", xbox::EMUPATCH(D3DDevice_SetPixelShaderConstant_4), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetPixelShader_0", xbox::EMUPATCH(D3DDevice_SetPixelShader_0), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetRenderState_Simple", xbox::EMUPATCH(D3DDevice_SetRenderState_Simple), PATCH_HLE_D3D),
PATCH_ENTRY("D3DDevice_SetRenderTarget", xbox::EMUPATCH(D3DDevice_SetRenderTarget), PATCH_HLE_D3D),