|
|
|
@ -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;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|