[3] | 1 | /* |
---|
| 2 | ----------------------------------------------------------------------------- |
---|
| 3 | This source file is part of OGRE |
---|
| 4 | (Object-oriented Graphics Rendering Engine) |
---|
| 5 | For the latest info, see http://www.ogre3d.org/ |
---|
| 6 | |
---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd |
---|
| 8 | Also see acknowledgements in Readme.html |
---|
| 9 | |
---|
| 10 | This program is free software; you can redistribute it and/or modify it under |
---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
| 13 | version. |
---|
| 14 | |
---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
| 18 | |
---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
| 23 | |
---|
| 24 | You may alternatively use this source under the terms of a specific version of |
---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
| 26 | Torus Knot Software Ltd. |
---|
| 27 | ----------------------------------------------------------------------------- |
---|
| 28 | */ |
---|
| 29 | |
---|
| 30 | |
---|
| 31 | /** |
---|
| 32 | A number of invaluable references were used to put together this ps.1.x compiler for ATI_fragment_shader execution |
---|
| 33 | |
---|
| 34 | References: |
---|
| 35 | 1. MSDN: DirectX 8.1 Reference |
---|
| 36 | 2. Wolfgang F. Engel "Fundamentals of Pixel Shaders - Introduction to Shader Programming Part III" on gamedev.net |
---|
| 37 | 3. Martin Ecker - XEngine |
---|
| 38 | 4. Shawn Kirst - ps14toATIfs |
---|
| 39 | 5. Jason L. Mitchell "Real-Time 3D Graphics With Pixel Shaders" |
---|
| 40 | 6. Jason L. Mitchell "1.4 Pixel Shaders" |
---|
| 41 | 7. Jason L. Mitchell and Evan Hart "Hardware Shading with EXT_vertex_shader and ATI_fragment_shader" |
---|
| 42 | 6. ATI 8500 SDK |
---|
| 43 | 7. GL_ATI_fragment_shader extension reference |
---|
| 44 | |
---|
| 45 | */ |
---|
| 46 | //--------------------------------------------------------------------------- |
---|
| 47 | #ifndef ps_1_4H |
---|
| 48 | #define ps_1_4H |
---|
| 49 | |
---|
| 50 | #include <stdio.h> |
---|
| 51 | #include <stdlib.h> |
---|
| 52 | #include <string.h> |
---|
| 53 | |
---|
| 54 | #include "OgreGLPrerequisites.h" |
---|
| 55 | #include "Compiler2Pass.h" |
---|
| 56 | |
---|
| 57 | |
---|
| 58 | //--------------------------------------------------------------------------- |
---|
| 59 | // macro to get the size of a static array |
---|
| 60 | #define ARRAYSIZE(array) (sizeof(array)/sizeof(array[0])) |
---|
| 61 | |
---|
| 62 | #define ALPHA_BIT 0x08 |
---|
| 63 | #define RGB_BITS 0x07 |
---|
| 64 | |
---|
| 65 | // Context key patterns |
---|
| 66 | #define ckp_PS_BASE 0x1 |
---|
| 67 | #define ckp_PS_1_1 0x2 |
---|
| 68 | #define ckp_PS_1_2 0x4 |
---|
| 69 | #define ckp_PS_1_3 0x8 |
---|
| 70 | #define ckp_PS_1_4 0x10 |
---|
| 71 | |
---|
| 72 | #define ckp_PS_1_4_BASE (ckp_PS_BASE + ckp_PS_1_4) |
---|
| 73 | |
---|
| 74 | |
---|
| 75 | |
---|
| 76 | |
---|
| 77 | /** Subclasses Compiler2Pass to provide a ps_1_x compiler that takes DirectX pixel shader assembly |
---|
| 78 | and converts it to a form that can be used by ATI_fragment_shader OpenGL API |
---|
| 79 | @remarks |
---|
| 80 | all ps_1_1, ps_1_2, ps_1_3, ps_1_4 assembly instructions are recognized but not all are passed |
---|
| 81 | on to ATI_fragment_shader. ATI_fragment_shader does not have an equivelant directive for |
---|
| 82 | texkill or texdepth instructions. |
---|
| 83 | |
---|
| 84 | The user must provide the GL binding interfaces. |
---|
| 85 | |
---|
| 86 | A Test method is provided to verify the basic operation of the compiler which outputs the test |
---|
| 87 | results to a file. |
---|
| 88 | |
---|
| 89 | |
---|
| 90 | */ |
---|
| 91 | class PS_1_4 : public Compiler2Pass{ |
---|
| 92 | private: |
---|
| 93 | enum RWAflags {rwa_NONE = 0, rwa_READ = 1, rwa_WRITE = 2}; |
---|
| 94 | |
---|
| 95 | enum MachineInstID {mi_COLOROP1, mi_COLOROP2, mi_COLOROP3, mi_ALPHAOP1, mi_ALPHAOP2, |
---|
| 96 | mi_ALPHAOP3, mi_SETCONSTANTS, mi_PASSTEXCOORD, mi_SAMPLEMAP, mi_TEX, |
---|
| 97 | mi_TEXCOORD, mi_TEXREG2RGB, mi_NOP |
---|
| 98 | }; |
---|
| 99 | |
---|
| 100 | struct TokenInstType{ |
---|
| 101 | char* Name; |
---|
| 102 | GLuint ID; |
---|
| 103 | |
---|
| 104 | }; |
---|
| 105 | |
---|
| 106 | struct RegisterUsage { |
---|
| 107 | bool Phase1Write; |
---|
| 108 | bool Phase2Write; |
---|
| 109 | }; |
---|
| 110 | |
---|
| 111 | // Token ID enumeration |
---|
| 112 | enum SymbolID { |
---|
| 113 | // Terminal Tokens section |
---|
| 114 | |
---|
| 115 | // DirectX pixel shader source formats |
---|
| 116 | sid_PS_1_4, sid_PS_1_1, sid_PS_1_2, sid_PS_1_3, |
---|
| 117 | |
---|
| 118 | // PS_BASE |
---|
| 119 | sid_C0, sid_C1, sid_C2, sid_C3, sid_C4, sid_C5, sid_C6, sid_C7, |
---|
| 120 | sid_V0, sid_V1, |
---|
| 121 | sid_ADD, sid_SUB, sid_MUL, sid_MAD, sid_LRP, sid_MOV, sid_CMP, sid_CND, |
---|
| 122 | sid_DP3, sid_DP4, sid_DEF, |
---|
| 123 | sid_R, sid_RA, sid_G, sid_GA, sid_B, sid_BA, sid_A, sid_RGBA, sid_RGB, |
---|
| 124 | sid_RG, sid_RGA, sid_RB, sid_RBA, sid_GB, sid_GBA, |
---|
| 125 | sid_RRRR, sid_GGGG, sid_BBBB, sid_AAAA, |
---|
| 126 | sid_X2, sid_X4, sid_D2, sid_SAT, |
---|
| 127 | sid_BIAS, sid_INVERT, sid_NEGATE, sid_BX2, |
---|
| 128 | sid_COMMA, sid_VALUE, |
---|
| 129 | |
---|
| 130 | //PS_1_4 sid |
---|
| 131 | sid_R0, sid_R1, sid_R2, sid_R3, sid_R4, sid_R5, |
---|
| 132 | sid_T0, sid_T1, sid_T2, sid_T3, sid_T4, sid_T5, |
---|
| 133 | sid_DP2ADD, |
---|
| 134 | sid_X8, sid_D8, sid_D4, |
---|
| 135 | sid_TEXCRD, sid_TEXLD, |
---|
| 136 | sid_STR, sid_STQ, |
---|
| 137 | sid_STRDR, sid_STQDQ, |
---|
| 138 | sid_BEM, |
---|
| 139 | sid_PHASE, |
---|
| 140 | |
---|
| 141 | //PS_1_1 sid |
---|
| 142 | sid_1R0, sid_1R1, sid_1T0, sid_1T1, sid_1T2, sid_1T3, |
---|
| 143 | sid_TEX, sid_TEXCOORD, sid_TEXM3X2PAD, |
---|
| 144 | sid_TEXM3X2TEX, sid_TEXM3X3PAD, sid_TEXM3X3TEX, sid_TEXM3X3SPEC, sid_TEXM3X3VSPEC, |
---|
| 145 | sid_TEXREG2AR, sid_TEXREG2GB, |
---|
| 146 | |
---|
| 147 | //PS_1_2 side |
---|
| 148 | sid_TEXREG2RGB, sid_TEXDP3, sid_TEXDP3TEX, |
---|
| 149 | |
---|
| 150 | // common |
---|
| 151 | sid_SKIP, sid_PLUS, |
---|
| 152 | |
---|
| 153 | // non-terminal tokens section |
---|
| 154 | sid_PROGRAM, sid_PROGRAMTYPE, sid_DECLCONSTS, sid_DEFCONST, |
---|
| 155 | sid_CONSTANT, sid_COLOR, |
---|
| 156 | sid_TEXSWIZZLE, sid_UNARYOP, |
---|
| 157 | sid_NUMVAL, sid_SEPERATOR, sid_ALUOPS, sid_TEXMASK, sid_TEXOP_PS1_1_3, |
---|
| 158 | sid_TEXOP_PS1_4, |
---|
| 159 | sid_ALU_STATEMENT, sid_DSTMODSAT, sid_UNARYOP_ARGS, sid_REG_PS1_4, |
---|
| 160 | sid_TEX_PS1_4, sid_REG_PS1_1_3, sid_TEX_PS1_1_3, sid_DSTINFO, |
---|
| 161 | sid_SRCINFO, sid_BINARYOP_ARGS, sid_TERNARYOP_ARGS, sid_TEMPREG, |
---|
| 162 | sid_DSTMASK, sid_PRESRCMOD, sid_SRCNAME, sid_SRCREP, sid_POSTSRCMOD, |
---|
| 163 | sid_DSTMOD, sid_DSTSAT, sid_BINARYOP, sid_TERNARYOP, |
---|
| 164 | sid_TEXOPS_PHASE1, sid_COISSUE, sid_PHASEMARKER, sid_TEXOPS_PHASE2, |
---|
| 165 | sid_TEXREG_PS1_4, sid_TEXOPS_PS1_4, sid_TEXOPS_PS1_1_3, sid_TEXCISCOP_PS1_1_3, |
---|
| 166 | |
---|
| 167 | |
---|
| 168 | // last token |
---|
| 169 | sid_INVALID = BAD_TOKEN // must be last in enumeration |
---|
| 170 | }; |
---|
| 171 | |
---|
| 172 | /// structure used to keep track of arguments and instruction parameters |
---|
| 173 | struct OpParram { |
---|
| 174 | GLuint Arg; // type of argument |
---|
| 175 | bool Filled; // has it been filled yet |
---|
| 176 | GLuint MaskRep; // Mask/Replicator flags |
---|
| 177 | GLuint Mod; // argument modifier |
---|
| 178 | }; |
---|
| 179 | |
---|
| 180 | typedef std::vector<uint> MachineInstContainer; |
---|
| 181 | //typedef MachineInstContainer::iterator MachineInstIterator; |
---|
| 182 | |
---|
| 183 | |
---|
| 184 | // there are 2 phases with 2 subphases each |
---|
| 185 | enum PhaseType {ptPHASE1TEX, ptPHASE1ALU, ptPHASE2TEX, ptPHASE2ALU }; |
---|
| 186 | |
---|
| 187 | struct RegModOffset { |
---|
| 188 | uint MacroOffset; |
---|
| 189 | uint RegisterBase; |
---|
| 190 | uint OpParramsIndex; |
---|
| 191 | }; |
---|
| 192 | |
---|
| 193 | struct MacroRegModify { |
---|
| 194 | TokenInst * Macro; |
---|
| 195 | uint MacroSize; |
---|
| 196 | RegModOffset * RegMods; |
---|
| 197 | uint RegModSize; |
---|
| 198 | |
---|
| 199 | }; |
---|
| 200 | |
---|
| 201 | #define R_BASE (sid_R0 - GL_REG_0_ATI) |
---|
| 202 | #define C_BASE (sid_C0 - GL_CON_0_ATI) |
---|
| 203 | #define T_BASE (sid_1T0 - GL_REG_0_ATI) |
---|
| 204 | |
---|
| 205 | // static library database for tokens and BNF rules |
---|
| 206 | static SymbolDef PS_1_4_SymbolTypeLib[]; |
---|
| 207 | static TokenRule PS_1_x_RulePath[]; |
---|
| 208 | static bool LibInitialized; |
---|
| 209 | |
---|
| 210 | // Static Macro database for ps.1.1 ps.1.2 ps.1.3 instructions |
---|
| 211 | |
---|
| 212 | static TokenInst texreg2ar[]; |
---|
| 213 | static RegModOffset texreg2xx_RegMods[]; |
---|
| 214 | static MacroRegModify texreg2ar_MacroMods; |
---|
| 215 | |
---|
| 216 | static TokenInst texreg2gb[]; |
---|
| 217 | static MacroRegModify texreg2gb_MacroMods; |
---|
| 218 | |
---|
| 219 | static TokenInst texdp3[]; |
---|
| 220 | static RegModOffset texdp3_RegMods[]; |
---|
| 221 | static MacroRegModify texdp3_MacroMods; |
---|
| 222 | |
---|
| 223 | static TokenInst texdp3tex[]; |
---|
| 224 | static RegModOffset texdp3tex_RegMods[]; |
---|
| 225 | static MacroRegModify texdp3tex_MacroMods; |
---|
| 226 | |
---|
| 227 | static TokenInst texm3x2pad[]; |
---|
| 228 | static RegModOffset texm3xxpad_RegMods[]; |
---|
| 229 | static MacroRegModify texm3x2pad_MacroMods; |
---|
| 230 | |
---|
| 231 | static TokenInst texm3x2tex[]; |
---|
| 232 | static RegModOffset texm3xxtex_RegMods[]; |
---|
| 233 | static MacroRegModify texm3x2tex_MacroMods; |
---|
| 234 | |
---|
| 235 | static TokenInst texm3x3pad[]; |
---|
| 236 | static MacroRegModify texm3x3pad_MacroMods; |
---|
| 237 | |
---|
| 238 | static TokenInst texm3x3tex[]; |
---|
| 239 | static MacroRegModify texm3x3tex_MacroMods; |
---|
| 240 | |
---|
| 241 | static TokenInst texm3x3spec[]; |
---|
| 242 | static RegModOffset texm3x3spec_RegMods[]; |
---|
| 243 | static MacroRegModify texm3x3spec_MacroMods; |
---|
| 244 | |
---|
| 245 | static TokenInst texm3x3vspec[]; |
---|
| 246 | static RegModOffset texm3x3vspec_RegMods[]; |
---|
| 247 | static MacroRegModify texm3x3vspec_MacroMods; |
---|
| 248 | |
---|
| 249 | |
---|
| 250 | MachineInstContainer mPhase1TEX_mi; /// machine instructions for phase one texture section |
---|
| 251 | MachineInstContainer mPhase1ALU_mi; /// machine instructions for phase one ALU section |
---|
| 252 | MachineInstContainer mPhase2TEX_mi; /// machine instructions for phase two texture section |
---|
| 253 | MachineInstContainer mPhase2ALU_mi; /// machine instructions for phase two ALU section |
---|
| 254 | |
---|
| 255 | MachineInstContainer* mActivePhaseMachineInstructions; |
---|
| 256 | // vars used during pass 2 |
---|
| 257 | MachineInstID mOpType; |
---|
| 258 | uint mOpInst; |
---|
| 259 | bool mDo_Alpha; |
---|
| 260 | PhaseType mInstructionPhase; |
---|
| 261 | int mArgCnt; |
---|
| 262 | int mConstantsPos; |
---|
| 263 | |
---|
| 264 | #define MAXOPPARRAMS 5 // max number of parrams bound to an instruction |
---|
| 265 | |
---|
| 266 | OpParram mOpParrams[MAXOPPARRAMS]; |
---|
| 267 | |
---|
| 268 | /// keeps track of which registers are written to in each phase |
---|
| 269 | /// if a register is read from but has not been written to in phase 2 |
---|
| 270 | /// then if it was written to in phase 1 perform a register pass function |
---|
| 271 | /// at the begining of phase2 so that the register has something worthwhile in it |
---|
| 272 | /// NB: check ALU and TEX section of phase 1 and phase 2 |
---|
| 273 | /// there are 6 temp registers r0 to r5 to keep track off |
---|
| 274 | /// checks are performed in pass 2 when building machine instructions |
---|
| 275 | RegisterUsage Phase_RegisterUsage[6]; |
---|
| 276 | |
---|
| 277 | bool mMacroOn; // if true then put all ALU instructions in phase 1 |
---|
| 278 | |
---|
| 279 | uint mTexm3x3padCount; // keep track of how many texm3x3pad instructions are used so know which mask to use |
---|
| 280 | |
---|
| 281 | size_t mLastInstructionPos; // keep track of last phase 2 ALU instruction to check for R0 setting |
---|
| 282 | size_t mSecondLastInstructionPos; |
---|
| 283 | |
---|
| 284 | // keep track if phase marker found: determines which phase the ALU instructions go into |
---|
| 285 | bool mPhaseMarkerFound; |
---|
| 286 | |
---|
| 287 | #ifdef _DEBUG |
---|
| 288 | FILE* fp; |
---|
| 289 | // full compiler test with output results going to a text file |
---|
| 290 | void testCompile(char* testname, char* teststr, SymbolID* testresult, |
---|
| 291 | uint testresultsize, GLuint* MachinInstResults = NULL, uint MachinInstResultsSize = 0); |
---|
| 292 | #endif // _DEBUG |
---|
| 293 | |
---|
| 294 | |
---|
| 295 | /** attempt to build a machine instruction using current tokens |
---|
| 296 | determines what phase machine insturction should be in and if an Alpha Op is required |
---|
| 297 | calls expandMachineInstruction() to expand the token into machine instructions |
---|
| 298 | */ |
---|
| 299 | bool BuildMachineInst(); |
---|
| 300 | |
---|
| 301 | void clearMachineInstState(); |
---|
| 302 | |
---|
| 303 | bool setOpParram(const SymbolDef* symboldef); |
---|
| 304 | |
---|
| 305 | /** optimizes machine instructions depending on pixel shader context |
---|
| 306 | only applies to ps.1.1 ps.1.2 and ps.1.3 since they use CISC instructions |
---|
| 307 | that must be transformed into RISC instructions |
---|
| 308 | */ |
---|
| 309 | void optimize(); |
---|
| 310 | |
---|
| 311 | // the method is expected to be recursive to allow for inline expansion of instructions if required |
---|
| 312 | bool Pass2scan(const TokenInst * Tokens, const size_t size); |
---|
| 313 | |
---|
| 314 | // supply virtual functions for Compiler2Pass |
---|
| 315 | /// Pass 1 is completed so now take tokens generated and build machine instructions |
---|
| 316 | bool doPass2(); |
---|
| 317 | |
---|
| 318 | /** Build a machine instruction from token and ready it for expansion |
---|
| 319 | will expand CISC tokens using macro database |
---|
| 320 | |
---|
| 321 | */ |
---|
| 322 | bool bindMachineInstInPassToFragmentShader(const MachineInstContainer & PassMachineInstructions); |
---|
| 323 | |
---|
| 324 | /** Expand CISC tokens into PS1_4 token equivalents |
---|
| 325 | |
---|
| 326 | */ |
---|
| 327 | bool expandMacro(const MacroRegModify & MacroMod); |
---|
| 328 | |
---|
| 329 | /** Expand Machine instruction into operation type and arguments and put into proper machine |
---|
| 330 | instruction container |
---|
| 331 | also expands scaler alpha machine instructions if required |
---|
| 332 | |
---|
| 333 | */ |
---|
| 334 | bool expandMachineInstruction(); |
---|
| 335 | |
---|
| 336 | // mainly used by tests - too slow for use in binding |
---|
| 337 | size_t getMachineInst(size_t Idx); |
---|
| 338 | |
---|
| 339 | size_t getMachineInstCount(); |
---|
| 340 | |
---|
| 341 | void addMachineInst(PhaseType phase, const uint inst); |
---|
| 342 | |
---|
| 343 | void clearAllMachineInst(); |
---|
| 344 | |
---|
| 345 | void updateRegisterWriteState(const PhaseType phase); |
---|
| 346 | |
---|
| 347 | bool isRegisterReadValid(const PhaseType phase, const int param); |
---|
| 348 | |
---|
| 349 | public: |
---|
| 350 | |
---|
| 351 | /// constructor |
---|
| 352 | PS_1_4(); |
---|
| 353 | |
---|
| 354 | /// binds machine instructions generated in Pass 2 to the ATI GL fragment shader |
---|
| 355 | bool bindAllMachineInstToFragmentShader(); |
---|
| 356 | |
---|
| 357 | #ifdef _DEBUG |
---|
| 358 | /// perform compiler tests - only available in _DEBUG mode |
---|
| 359 | void test(); |
---|
| 360 | void testbinder(); |
---|
| 361 | |
---|
| 362 | #endif |
---|
| 363 | }; |
---|
| 364 | |
---|
| 365 | |
---|
| 366 | #endif |
---|
| 367 | |
---|