/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ /** A number of invaluable references were used to put together this ps.1.x compiler for ATI_fragment_shader execution References: 1. MSDN: DirectX 8.1 Reference 2. Wolfgang F. Engel "Fundamentals of Pixel Shaders - Introduction to Shader Programming Part III" on gamedev.net 3. Martin Ecker - XEngine 4. Shawn Kirst - ps14toATIfs 5. Jason L. Mitchell "Real-Time 3D Graphics With Pixel Shaders" 6. Jason L. Mitchell "1.4 Pixel Shaders" 7. Jason L. Mitchell and Evan Hart "Hardware Shading with EXT_vertex_shader and ATI_fragment_shader" 6. ATI 8500 SDK 7. GL_ATI_fragment_shader extension reference */ //--------------------------------------------------------------------------- #ifndef ps_1_4H #define ps_1_4H #include #include #include #include "OgreGLPrerequisites.h" #include "Compiler2Pass.h" //--------------------------------------------------------------------------- // macro to get the size of a static array #define ARRAYSIZE(array) (sizeof(array)/sizeof(array[0])) #define ALPHA_BIT 0x08 #define RGB_BITS 0x07 // Context key patterns #define ckp_PS_BASE 0x1 #define ckp_PS_1_1 0x2 #define ckp_PS_1_2 0x4 #define ckp_PS_1_3 0x8 #define ckp_PS_1_4 0x10 #define ckp_PS_1_4_BASE (ckp_PS_BASE + ckp_PS_1_4) /** Subclasses Compiler2Pass to provide a ps_1_x compiler that takes DirectX pixel shader assembly and converts it to a form that can be used by ATI_fragment_shader OpenGL API @remarks all ps_1_1, ps_1_2, ps_1_3, ps_1_4 assembly instructions are recognized but not all are passed on to ATI_fragment_shader. ATI_fragment_shader does not have an equivelant directive for texkill or texdepth instructions. The user must provide the GL binding interfaces. A Test method is provided to verify the basic operation of the compiler which outputs the test results to a file. */ class PS_1_4 : public Compiler2Pass{ private: enum RWAflags {rwa_NONE = 0, rwa_READ = 1, rwa_WRITE = 2}; enum MachineInstID {mi_COLOROP1, mi_COLOROP2, mi_COLOROP3, mi_ALPHAOP1, mi_ALPHAOP2, mi_ALPHAOP3, mi_SETCONSTANTS, mi_PASSTEXCOORD, mi_SAMPLEMAP, mi_TEX, mi_TEXCOORD, mi_TEXREG2RGB, mi_NOP }; struct TokenInstType{ char* Name; GLuint ID; }; struct RegisterUsage { bool Phase1Write; bool Phase2Write; }; // Token ID enumeration enum SymbolID { // Terminal Tokens section // DirectX pixel shader source formats sid_PS_1_4, sid_PS_1_1, sid_PS_1_2, sid_PS_1_3, // PS_BASE sid_C0, sid_C1, sid_C2, sid_C3, sid_C4, sid_C5, sid_C6, sid_C7, sid_V0, sid_V1, sid_ADD, sid_SUB, sid_MUL, sid_MAD, sid_LRP, sid_MOV, sid_CMP, sid_CND, sid_DP3, sid_DP4, sid_DEF, sid_R, sid_RA, sid_G, sid_GA, sid_B, sid_BA, sid_A, sid_RGBA, sid_RGB, sid_RG, sid_RGA, sid_RB, sid_RBA, sid_GB, sid_GBA, sid_RRRR, sid_GGGG, sid_BBBB, sid_AAAA, sid_X2, sid_X4, sid_D2, sid_SAT, sid_BIAS, sid_INVERT, sid_NEGATE, sid_BX2, sid_COMMA, sid_VALUE, //PS_1_4 sid sid_R0, sid_R1, sid_R2, sid_R3, sid_R4, sid_R5, sid_T0, sid_T1, sid_T2, sid_T3, sid_T4, sid_T5, sid_DP2ADD, sid_X8, sid_D8, sid_D4, sid_TEXCRD, sid_TEXLD, sid_STR, sid_STQ, sid_STRDR, sid_STQDQ, sid_BEM, sid_PHASE, //PS_1_1 sid sid_1R0, sid_1R1, sid_1T0, sid_1T1, sid_1T2, sid_1T3, sid_TEX, sid_TEXCOORD, sid_TEXM3X2PAD, sid_TEXM3X2TEX, sid_TEXM3X3PAD, sid_TEXM3X3TEX, sid_TEXM3X3SPEC, sid_TEXM3X3VSPEC, sid_TEXREG2AR, sid_TEXREG2GB, //PS_1_2 side sid_TEXREG2RGB, sid_TEXDP3, sid_TEXDP3TEX, // common sid_SKIP, sid_PLUS, // non-terminal tokens section sid_PROGRAM, sid_PROGRAMTYPE, sid_DECLCONSTS, sid_DEFCONST, sid_CONSTANT, sid_COLOR, sid_TEXSWIZZLE, sid_UNARYOP, sid_NUMVAL, sid_SEPERATOR, sid_ALUOPS, sid_TEXMASK, sid_TEXOP_PS1_1_3, sid_TEXOP_PS1_4, sid_ALU_STATEMENT, sid_DSTMODSAT, sid_UNARYOP_ARGS, sid_REG_PS1_4, sid_TEX_PS1_4, sid_REG_PS1_1_3, sid_TEX_PS1_1_3, sid_DSTINFO, sid_SRCINFO, sid_BINARYOP_ARGS, sid_TERNARYOP_ARGS, sid_TEMPREG, sid_DSTMASK, sid_PRESRCMOD, sid_SRCNAME, sid_SRCREP, sid_POSTSRCMOD, sid_DSTMOD, sid_DSTSAT, sid_BINARYOP, sid_TERNARYOP, sid_TEXOPS_PHASE1, sid_COISSUE, sid_PHASEMARKER, sid_TEXOPS_PHASE2, sid_TEXREG_PS1_4, sid_TEXOPS_PS1_4, sid_TEXOPS_PS1_1_3, sid_TEXCISCOP_PS1_1_3, // last token sid_INVALID = BAD_TOKEN // must be last in enumeration }; /// structure used to keep track of arguments and instruction parameters struct OpParram { GLuint Arg; // type of argument bool Filled; // has it been filled yet GLuint MaskRep; // Mask/Replicator flags GLuint Mod; // argument modifier }; typedef std::vector MachineInstContainer; //typedef MachineInstContainer::iterator MachineInstIterator; // there are 2 phases with 2 subphases each enum PhaseType {ptPHASE1TEX, ptPHASE1ALU, ptPHASE2TEX, ptPHASE2ALU }; struct RegModOffset { uint MacroOffset; uint RegisterBase; uint OpParramsIndex; }; struct MacroRegModify { TokenInst * Macro; uint MacroSize; RegModOffset * RegMods; uint RegModSize; }; #define R_BASE (sid_R0 - GL_REG_0_ATI) #define C_BASE (sid_C0 - GL_CON_0_ATI) #define T_BASE (sid_1T0 - GL_REG_0_ATI) // static library database for tokens and BNF rules static SymbolDef PS_1_4_SymbolTypeLib[]; static TokenRule PS_1_x_RulePath[]; static bool LibInitialized; // Static Macro database for ps.1.1 ps.1.2 ps.1.3 instructions static TokenInst texreg2ar[]; static RegModOffset texreg2xx_RegMods[]; static MacroRegModify texreg2ar_MacroMods; static TokenInst texreg2gb[]; static MacroRegModify texreg2gb_MacroMods; static TokenInst texdp3[]; static RegModOffset texdp3_RegMods[]; static MacroRegModify texdp3_MacroMods; static TokenInst texdp3tex[]; static RegModOffset texdp3tex_RegMods[]; static MacroRegModify texdp3tex_MacroMods; static TokenInst texm3x2pad[]; static RegModOffset texm3xxpad_RegMods[]; static MacroRegModify texm3x2pad_MacroMods; static TokenInst texm3x2tex[]; static RegModOffset texm3xxtex_RegMods[]; static MacroRegModify texm3x2tex_MacroMods; static TokenInst texm3x3pad[]; static MacroRegModify texm3x3pad_MacroMods; static TokenInst texm3x3tex[]; static MacroRegModify texm3x3tex_MacroMods; static TokenInst texm3x3spec[]; static RegModOffset texm3x3spec_RegMods[]; static MacroRegModify texm3x3spec_MacroMods; static TokenInst texm3x3vspec[]; static RegModOffset texm3x3vspec_RegMods[]; static MacroRegModify texm3x3vspec_MacroMods; MachineInstContainer mPhase1TEX_mi; /// machine instructions for phase one texture section MachineInstContainer mPhase1ALU_mi; /// machine instructions for phase one ALU section MachineInstContainer mPhase2TEX_mi; /// machine instructions for phase two texture section MachineInstContainer mPhase2ALU_mi; /// machine instructions for phase two ALU section MachineInstContainer* mActivePhaseMachineInstructions; // vars used during pass 2 MachineInstID mOpType; uint mOpInst; bool mDo_Alpha; PhaseType mInstructionPhase; int mArgCnt; int mConstantsPos; #define MAXOPPARRAMS 5 // max number of parrams bound to an instruction OpParram mOpParrams[MAXOPPARRAMS]; /// keeps track of which registers are written to in each phase /// if a register is read from but has not been written to in phase 2 /// then if it was written to in phase 1 perform a register pass function /// at the begining of phase2 so that the register has something worthwhile in it /// NB: check ALU and TEX section of phase 1 and phase 2 /// there are 6 temp registers r0 to r5 to keep track off /// checks are performed in pass 2 when building machine instructions RegisterUsage Phase_RegisterUsage[6]; bool mMacroOn; // if true then put all ALU instructions in phase 1 uint mTexm3x3padCount; // keep track of how many texm3x3pad instructions are used so know which mask to use size_t mLastInstructionPos; // keep track of last phase 2 ALU instruction to check for R0 setting size_t mSecondLastInstructionPos; // keep track if phase marker found: determines which phase the ALU instructions go into bool mPhaseMarkerFound; #ifdef _DEBUG FILE* fp; // full compiler test with output results going to a text file void testCompile(char* testname, char* teststr, SymbolID* testresult, uint testresultsize, GLuint* MachinInstResults = NULL, uint MachinInstResultsSize = 0); #endif // _DEBUG /** attempt to build a machine instruction using current tokens determines what phase machine insturction should be in and if an Alpha Op is required calls expandMachineInstruction() to expand the token into machine instructions */ bool BuildMachineInst(); void clearMachineInstState(); bool setOpParram(const SymbolDef* symboldef); /** optimizes machine instructions depending on pixel shader context only applies to ps.1.1 ps.1.2 and ps.1.3 since they use CISC instructions that must be transformed into RISC instructions */ void optimize(); // the method is expected to be recursive to allow for inline expansion of instructions if required bool Pass2scan(const TokenInst * Tokens, const size_t size); // supply virtual functions for Compiler2Pass /// Pass 1 is completed so now take tokens generated and build machine instructions bool doPass2(); /** Build a machine instruction from token and ready it for expansion will expand CISC tokens using macro database */ bool bindMachineInstInPassToFragmentShader(const MachineInstContainer & PassMachineInstructions); /** Expand CISC tokens into PS1_4 token equivalents */ bool expandMacro(const MacroRegModify & MacroMod); /** Expand Machine instruction into operation type and arguments and put into proper machine instruction container also expands scaler alpha machine instructions if required */ bool expandMachineInstruction(); // mainly used by tests - too slow for use in binding size_t getMachineInst(size_t Idx); size_t getMachineInstCount(); void addMachineInst(PhaseType phase, const uint inst); void clearAllMachineInst(); void updateRegisterWriteState(const PhaseType phase); bool isRegisterReadValid(const PhaseType phase, const int param); public: /// constructor PS_1_4(); /// binds machine instructions generated in Pass 2 to the ATI GL fragment shader bool bindAllMachineInstToFragmentShader(); #ifdef _DEBUG /// perform compiler tests - only available in _DEBUG mode void test(); void testbinder(); #endif }; #endif