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