📄 ps_1_4.cpp
字号:
case sid_CMP:
case sid_CND:
case sid_DP2ADD:
case sid_DP3:
case sid_DP4:
mOpType = (MachineInstID)(mi_COLOROP1 + mArgCnt - 1);
// if context is ps.1.x and Macro not on or a phase marker was found then put all ALU ops in phase 2 ALU container
if (((mActiveContexts & ckp_PS_1_1) && !mMacroOn) || mPhaseMarkerFound) mInstructionPhase = ptPHASE2ALU;
else mInstructionPhase = ptPHASE1ALU;
// check for alpha op in destination register which is OpParrams[0]
// if no Mask for destination then make it .rgba
if(mOpParrams[0].MaskRep == 0) mOpParrams[0].MaskRep =
GL_RED_BIT_ATI | GL_GREEN_BIT_ATI | GL_BLUE_BIT_ATI | ALPHA_BIT;
if (mOpParrams[0].MaskRep & ALPHA_BIT) {
mDo_Alpha = true;
mOpParrams[0].MaskRep -= ALPHA_BIT;
if(mOpParrams[0].MaskRep == 0) mOpType = mi_NOP; // only do alpha op
}
break;
case sid_TEXCRD:
mOpType = mi_PASSTEXCOORD;
if (mPhaseMarkerFound) mInstructionPhase = ptPHASE2TEX;
else mInstructionPhase = ptPHASE1TEX;
break;
case sid_TEXLD:
mOpType = mi_SAMPLEMAP;
if (mPhaseMarkerFound) mInstructionPhase = ptPHASE2TEX;
else mInstructionPhase = ptPHASE1TEX;
break;
case sid_TEX: // PS_1_1 emulation
mOpType = mi_TEX;
mInstructionPhase = ptPHASE1TEX;
break;
case sid_TEXCOORD: // PS_1_1 emulation
mOpType = mi_TEXCOORD;
mInstructionPhase = ptPHASE1TEX;
break;
case sid_TEXREG2AR:
passed = expandMacro(texreg2ar_MacroMods);
break;
case sid_TEXREG2GB:
passed = expandMacro(texreg2gb_MacroMods);
break;
case sid_TEXDP3:
passed = expandMacro(texdp3_MacroMods);
break;
case sid_TEXDP3TEX:
passed = expandMacro(texdp3tex_MacroMods);
break;
case sid_TEXM3X2PAD:
passed = expandMacro(texm3x2pad_MacroMods);
break;
case sid_TEXM3X2TEX:
passed = expandMacro(texm3x2tex_MacroMods);
break;
case sid_TEXM3X3PAD:
// only 2 texm3x3pad instructions allowed
// use count to modify macro to select which mask to use
if(mTexm3x3padCount<2) {
texm3x3pad[4].mID = sid_R + mTexm3x3padCount;
mTexm3x3padCount++;
passed = expandMacro(texm3x3pad_MacroMods);
}
else passed = false;
break;
case sid_TEXM3X3TEX:
passed = expandMacro(texm3x3tex_MacroMods);
break;
case sid_DEF:
mOpType = mi_SETCONSTANTS;
mInstructionPhase = ptPHASE1TEX;
break;
case sid_PHASE: // PS_1_4 only
mPhaseMarkerFound = true;
break;
} // end of switch
if(passed) passed = expandMachineInstruction();
return passed;
}
bool PS_1_4::expandMachineInstruction()
{
// now push instructions onto MachineInstructions container
// assume that an instruction will be expanded
bool passed = true;
if (mOpType != mi_NOP) {
// a machine instruction will be built
// this is currently the last one being built so keep track of it
if (mInstructionPhase == ptPHASE2ALU) {
mSecondLastInstructionPos = mLastInstructionPos;
mLastInstructionPos = mPhase2ALU_mi.size();
}
switch (mOpType) {
case mi_COLOROP1:
case mi_COLOROP2:
case mi_COLOROP3:
{
addMachineInst(mInstructionPhase, mOpType);
addMachineInst(mInstructionPhase, mSymbolTypeLib[mOpInst].mPass2Data);
// send all parameters to machine inst container
for(int i=0; i<=mArgCnt; i++) {
addMachineInst(mInstructionPhase, mOpParrams[i].Arg);
addMachineInst(mInstructionPhase, mOpParrams[i].MaskRep);
addMachineInst(mInstructionPhase, mOpParrams[i].Mod);
// check if source register read is valid in this phase
passed &= isRegisterReadValid(mInstructionPhase, i);
}
// record which registers were written to and in which phase
// mOpParrams[0].Arg is always the destination register r0 -> r5
updateRegisterWriteState(mInstructionPhase);
}
break;
case mi_SETCONSTANTS:
addMachineInst(mInstructionPhase, mOpType);
addMachineInst(mInstructionPhase, mOpParrams[0].Arg); // dst
addMachineInst(mInstructionPhase, mConstantsPos); // index into constants array
break;
case mi_PASSTEXCOORD:
case mi_SAMPLEMAP:
// if source is a temp register than place instruction in phase 2 Texture ops
if ((mOpParrams[1].Arg >= GL_REG_0_ATI) && (mOpParrams[1].Arg <= GL_REG_5_ATI)) {
mInstructionPhase = ptPHASE2TEX;
}
addMachineInst(mInstructionPhase, mOpType);
addMachineInst(mInstructionPhase, mOpParrams[0].Arg); // dst
addMachineInst(mInstructionPhase, mOpParrams[1].Arg); // coord
addMachineInst(mInstructionPhase, mOpParrams[1].MaskRep + GL_SWIZZLE_STR_ATI); // swizzle
// record which registers were written to and in which phase
// mOpParrams[0].Arg is always the destination register r0 -> r5
updateRegisterWriteState(mInstructionPhase);
break;
case mi_TEX: // PS_1_1 emulation - turn CISC into RISC - phase 1
addMachineInst(mInstructionPhase, mi_SAMPLEMAP);
addMachineInst(mInstructionPhase, mOpParrams[0].Arg); // dst
// tex tx becomes texld rx, tx with x: 0 - 3
addMachineInst(mInstructionPhase, mOpParrams[0].Arg - GL_REG_0_ATI + GL_TEXTURE0_ARB); // interp
// default to str which fills rgb of destination register
addMachineInst(mInstructionPhase, GL_SWIZZLE_STR_ATI); // swizzle
// record which registers were written to and in which phase
// mOpParrams[0].Arg is always the destination register r0 -> r5
updateRegisterWriteState(mInstructionPhase);
break;
case mi_TEXCOORD: // PS_1_1 emulation - turn CISC into RISC - phase 1
addMachineInst(mInstructionPhase, mi_PASSTEXCOORD);
addMachineInst(mInstructionPhase, mOpParrams[0].Arg); // dst
// texcoord tx becomes texcrd rx, tx with x: 0 - 3
addMachineInst(mInstructionPhase, mOpParrams[0].Arg - GL_REG_0_ATI + GL_TEXTURE0_ARB); // interp
// default to str which fills rgb of destination register
addMachineInst(mInstructionPhase, GL_SWIZZLE_STR_ATI); // swizzle
// record which registers were written to and in which phase
// mOpParrams[0].Arg is always the destination register r0 -> r5
updateRegisterWriteState(mInstructionPhase);
break;
} // end of switch (mOpType)
} // end of if (mOpType != mi_NOP)
if(mDo_Alpha) {
// process alpha channel
//
// a scaler machine instruction will be built
// this is currently the last one being built so keep track of it
if (mInstructionPhase == ptPHASE2ALU) {
mSecondLastInstructionPos = mLastInstructionPos;
mLastInstructionPos = mPhase2ALU_mi.size();
}
MachineInstID alphaoptype = (MachineInstID)(mi_ALPHAOP1 + mArgCnt - 1);
addMachineInst(mInstructionPhase, alphaoptype);
addMachineInst(mInstructionPhase, mSymbolTypeLib[mOpInst].mPass2Data);
// put all parameters in instruction que
for(int i=0; i<=mArgCnt; i++) {
addMachineInst(mInstructionPhase, mOpParrams[i].Arg);
// destination parameter has no mask since it is the alpha channel
// don't push mask for parrameter 0 (dst)
if(i>0) addMachineInst(mInstructionPhase, mOpParrams[i].MaskRep);
addMachineInst(mInstructionPhase, mOpParrams[i].Mod);
// check if source register read is valid in this phase
passed &= isRegisterReadValid(mInstructionPhase, i);
}
updateRegisterWriteState(mInstructionPhase);
}
// instruction passed on to machine instruction so clear the pipe
clearMachineInstState();
return passed;
}
void PS_1_4::updateRegisterWriteState(const PhaseType phase)
{
int reg_offset = mOpParrams[0].Arg - GL_REG_0_ATI;
switch(phase) {
case ptPHASE1TEX:
case ptPHASE1ALU:
Phase_RegisterUsage[reg_offset].Phase1Write = true;
break;
case ptPHASE2TEX:
case ptPHASE2ALU:
Phase_RegisterUsage[reg_offset].Phase2Write = true;
break;
} // end switch(phase)
}
bool PS_1_4::isRegisterReadValid(const PhaseType phase, const int param)
{
bool passed = true; // assume everything will go alright
// if in phase 2 ALU and argument is a source
if((phase == ptPHASE2ALU) && (param>0)) {
// is source argument a temp register r0 - r5?
if((mOpParrams[param].Arg >= GL_REG_0_ATI) && (mOpParrams[param].Arg <= GL_REG_5_ATI)) {
int reg_offset = mOpParrams[param].Arg - GL_REG_0_ATI;
// if register was not written to in phase 2 but was in phase 1
if((Phase_RegisterUsage[reg_offset].Phase2Write == false) && Phase_RegisterUsage[reg_offset].Phase1Write) {
// only perform register pass if there are ALU instructions in phase 1
if(mPhase1ALU_mi.size() > 0) {
// build machine instructions for passing a register from phase 1 to phase 2
// NB: only rgb components of register will get passed
addMachineInst(ptPHASE2TEX, mi_PASSTEXCOORD);
addMachineInst(ptPHASE2TEX, mOpParrams[param].Arg); // dst
addMachineInst(ptPHASE2TEX, mOpParrams[param].Arg); // coord
addMachineInst(ptPHASE2TEX, GL_SWIZZLE_STR_ATI); // swizzle
// mark register as being written to
Phase_RegisterUsage[reg_offset].Phase2Write = true;
}
}
// register can not be used because it has not been written to previously
else passed = false;
}
}
return passed;
}
void PS_1_4::optimize()
{
// perform some optimizations on ps.1.1 machine instructions
if (mActiveContexts & ckp_PS_1_1) {
// need to check last few instructions to make sure r0 is set
// ps.1.1 emulation uses r4 for r0 so last couple of instructions will probably require
// changine destination register back to r0
if (mLastInstructionPos < mPhase2ALU_mi.size()) {
// first argument at mLastInstructionPos + 2 is destination register for all ps.1.1 ALU instructions
mPhase2ALU_mi[mLastInstructionPos + 2] = GL_REG_0_ATI;
// if was an alpha op only then modify second last instruction destination register
if ((mPhase2ALU_mi[mLastInstructionPos] == mi_ALPHAOP1) ||
(mPhase2ALU_mi[mLastInstructionPos] == mi_ALPHAOP2) ||
(mPhase2ALU_mi[mLastInstructionPos] == mi_ALPHAOP3)
) {
mPhase2ALU_mi[mSecondLastInstructionPos + 2] = GL_REG_0_ATI;
}
}// end if (mLastInstructionPos < mMachineInstructions.size())
}// end if (mActiveContexts & ckp_PS_1_1)
}
void PS_1_4::clearMachineInstState()
{
// set current Machine Instruction State to baseline
mOpType = mi_NOP;
mOpInst = sid_INVALID;
mDo_Alpha = false;
mArgCnt = 0;
for(int i=0; i<MAXOPPARRAMS; i++) {
mOpParrams[i].Arg = GL_NONE;
mOpParrams[i].Filled = false;
mOpParrams[i].MaskRep = GL_NONE;
mOpParrams[i].Mod = GL_NONE;
}
}
void PS_1_4::clearAllMachineInst()
{
mPhase1TEX_mi.clear();
mPhase1ALU_mi.clear();
mPhase2TEX_mi.clear();
mPhase2ALU_mi.clear();
// reset write state for all registers
for(int i = 0; i<6; i++) {
Phase_RegisterUsage[i].Phase1Write = false;
Phase_RegisterUsage[i].Phase2Write = false;
}
mPhaseMarkerFound = false;
mConstantsPos = -4;
// keep track of the last instruction built
// this info is used at the end of pass 2 to optimize the machine code
mLastInstructionPos = 0;
mSecondLastInstructionPos = 0;
mMacroOn = false; // macro's off at the beginning
mTexm3x3padCount = 0;
}
bool PS_1_4::doPass2()
{
clearAllMachineInst();
// if pass 2 was successful, optimize the machine instructions
bool passed = Pass2scan(&mTokenInstructions[0], mTokenInstructions.size());
if (passed) optimize();
return passed;
}
bool PS_1_4::Pass2scan(const TokenInst * Tokens, const size_t size)
{
// execute TokenInstructions to build MachineInstructions
bool passed = true;
SymbolDef* cursymboldef;
uint ActiveNTTRuleID;
clearMachineInstState();
// iterate through all the tokens and build machine instruction
// for each machine instruction need: optype, opinst, and up to 5 parameters
for(uint i = 0; i < size; i++) {
// lookup instruction type in library
cursymboldef = &mSymbolTypeLib[Tokens[i].mID];
ActiveNTTRuleID = Tokens[i].mNTTRuleID;
mCurrentLine = Tokens[i].mLine;
mCharPos = Tokens[i].mPos;
switch(ActiveNTTRuleID) {
case sid_CONSTANT:
case sid_COLOR:
case sid_REG_PS1_4:
case sid_TEX_PS1_4:
case sid_REG_PS1_1_3:
case sid_TEX_PS1_1_3:
// registars can be used for read and write so they can be used for dst and arg
passed = setOpParram(cursymboldef);
break;
case sid_DEFCONST:
case sid_UNARYOP:
case sid_BINARYOP:
case sid_TERNARYOP:
case sid_TEXOP_PS1_1_3:
case sid_TEXOP_PS1_4:
case sid_PHASEMARKER:
case sid_TEXCISCOP_PS1_1_3:
// if the last instruction has not been passed on then do it now
// make sure the pipe is clear for a new instruction
BuildMachineInst();
if(mOpInst == sid_INVALID) {
mOpInst = cursymboldef->mID;
}
else passed = false;
break;
case sid_DSTMASK:
case sid_SRCREP:
case sid_TEXSWIZZLE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -