progman: Added Hebrew translation.
[wine] / dlls / d3dcompiler_43 / asmparser.c
1 /*
2  * Direct3D asm shader parser
3  *
4  * Copyright 2008 Stefan Dösinger
5  * Copyright 2009 Matteo Bruni
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wine/debug.h"
26
27 #include "d3dcompiler_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
30 WINE_DECLARE_DEBUG_CHANNEL(parsed_shader);
31
32
33 /* How to map vs 1.0 and 2.0 varyings to 3.0 ones
34  * oTx is mapped to ox, which happens to be an
35  * identical mapping since BWRITERSPR_TEXCRDOUT == BWRITERSPR_OUTPUT
36  * oPos, oFog and point size are mapped to general output regs as well.
37  * the vs 1.x and 2.x parser functions add varying declarations
38  * to the shader, and the 1.x and 2.x output functions check those varyings
39  */
40 #define OT0_REG         0
41 #define OT1_REG         1
42 #define OT2_REG         2
43 #define OT3_REG         3
44 #define OT4_REG         4
45 #define OT5_REG         5
46 #define OT6_REG         6
47 #define OT7_REG         7
48 #define OPOS_REG        8
49 #define OFOG_REG        9
50 #define OFOG_WRITEMASK  BWRITERSP_WRITEMASK_0
51 #define OPTS_REG        9
52 #define OPTS_WRITEMASK  BWRITERSP_WRITEMASK_1
53 #define OD0_REG         10
54 #define OD1_REG         11
55
56 /* Input color registers 0-1 are identically mapped */
57 #define C0_VARYING      0
58 #define C1_VARYING      1
59 #define T0_VARYING      2
60 #define T1_VARYING      3
61 #define T2_VARYING      4
62 #define T3_VARYING      5
63 #define T4_VARYING      6
64 #define T5_VARYING      7
65 #define T6_VARYING      8
66 #define T7_VARYING      9
67
68 /****************************************************************
69  * Common(non-version specific) shader parser control code      *
70  ****************************************************************/
71
72 static void asmparser_end(struct asm_parser *This) {
73     TRACE("Finalizing shader\n");
74 }
75
76 static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) {
77     if(!This->shader) return;
78     TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf);
79     TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w);
80     if(!add_constF(This->shader, reg, x, y, z, w)) {
81         ERR("Out of memory\n");
82         set_parse_status(This, PARSE_ERR);
83     }
84 }
85
86 static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) {
87     if(!This->shader) return;
88     TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb);
89     TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false");
90     if(!add_constB(This->shader, reg, x)) {
91         ERR("Out of memory\n");
92         set_parse_status(This, PARSE_ERR);
93     }
94 }
95
96 static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) {
97     if(!This->shader) return;
98     TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci);
99     TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w);
100     if(!add_constI(This->shader, reg, x, y, z, w)) {
101         ERR("Out of memory\n");
102         set_parse_status(This, PARSE_ERR);
103     }
104 }
105
106 static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num,
107                                  const struct shader_reg *reg) {
108     if(!This->shader) return;
109     if(This->shader->type == ST_PIXEL) {
110         asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no);
111         set_parse_status(This, PARSE_ERR);
112     }
113     if(!record_declaration(This->shader, usage, num, 0, TRUE, reg->regnum, reg->u.writemask, FALSE)) {
114         ERR("Out of memory\n");
115         set_parse_status(This, PARSE_ERR);
116     }
117 }
118
119 static void asmparser_dcl_output_unsupported(struct asm_parser *This, DWORD usage, DWORD num,
120                                              const struct shader_reg *reg) {
121     asmparser_message(This, "Line %u: Output declaration unsupported in this shader version\n", This->line_no);
122     set_parse_status(This, PARSE_ERR);
123 }
124
125 static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num,
126                                 DWORD mod, const struct shader_reg *reg) {
127     struct instruction instr;
128
129     if(!This->shader) return;
130     if(mod != 0 &&
131        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
132         (mod != BWRITERSPDM_MSAMPCENTROID &&
133          mod != BWRITERSPDM_PARTIALPRECISION))) {
134         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
135         set_parse_status(This, PARSE_ERR);
136         return;
137     }
138
139     /* Check register type and modifiers */
140     instr.dstmod = mod;
141     instr.shift = 0;
142     This->funcs->dstreg(This, &instr, reg);
143
144     if(!record_declaration(This->shader, usage, num, mod, FALSE, reg->regnum, reg->u.writemask, FALSE)) {
145         ERR("Out of memory\n");
146         set_parse_status(This, PARSE_ERR);
147     }
148 }
149
150 static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD num,
151                                      DWORD mod, const struct shader_reg *reg) {
152     struct instruction instr;
153
154     if(!This->shader) return;
155     instr.dstmod = mod;
156     instr.shift = 0;
157     This->funcs->dstreg(This, &instr, reg);
158     if(!record_declaration(This->shader, usage, num, mod, FALSE, instr.dst.regnum, instr.dst.u.writemask, FALSE)) {
159         ERR("Out of memory\n");
160         set_parse_status(This, PARSE_ERR);
161     }
162 }
163
164 static void asmparser_dcl_input_unsupported(struct asm_parser *This,
165         DWORD usage, DWORD num, DWORD mod, const struct shader_reg *reg)
166 {
167     asmparser_message(This, "Line %u: Input declaration unsupported in this shader version\n", This->line_no);
168     set_parse_status(This, PARSE_ERR);
169 }
170
171 static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype,
172                                   DWORD mod, DWORD regnum,
173                                   unsigned int line_no) {
174     if(!This->shader) return;
175     if(mod != 0 &&
176        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
177         (mod != BWRITERSPDM_MSAMPCENTROID &&
178          mod != BWRITERSPDM_PARTIALPRECISION))) {
179         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
180         set_parse_status(This, PARSE_ERR);
181         return;
182     }
183     if(!record_sampler(This->shader, samptype, mod, regnum)) {
184         ERR("Out of memory\n");
185         set_parse_status(This, PARSE_ERR);
186     }
187 }
188
189 static void asmparser_dcl_sampler_unsupported(struct asm_parser *This,
190         DWORD samptype, DWORD mod, DWORD regnum, unsigned int line_no)
191 {
192     asmparser_message(This, "Line %u: Sampler declaration unsupported in this shader version\n", This->line_no);
193     set_parse_status(This, PARSE_ERR);
194 }
195
196 static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
197                              const struct shader_reg *dst,
198                              const struct src_regs *srcs) {
199     struct instruction *instr;
200
201     if(!srcs || srcs->count != 3) {
202         asmparser_message(This, "Line %u: sincos (vs 2) has an incorrect number of source registers\n", This->line_no);
203         set_parse_status(This, PARSE_ERR);
204         return;
205     }
206
207     instr = alloc_instr(3);
208     if(!instr) {
209         ERR("Error allocating memory for the instruction\n");
210         set_parse_status(This, PARSE_ERR);
211         return;
212     }
213
214     instr->opcode = BWRITERSIO_SINCOS;
215     instr->dstmod = mod;
216     instr->shift = shift;
217     instr->comptype = 0;
218
219     This->funcs->dstreg(This, instr, dst);
220     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
221     This->funcs->srcreg(This, instr, 1, &srcs->reg[1]);
222     This->funcs->srcreg(This, instr, 2, &srcs->reg[2]);
223
224     if(!add_instruction(This->shader, instr)) {
225         ERR("Out of memory\n");
226         set_parse_status(This, PARSE_ERR);
227     }
228 }
229
230 static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
231     struct shader_reg ret;
232     switch(reg->type) {
233         case BWRITERSPR_TEXTURE:
234             if(tex_varying) {
235                 ret = *reg;
236                 ret.type = BWRITERSPR_INPUT;
237                 switch(reg->regnum) {
238                     case 0:     ret.regnum = T0_VARYING; break;
239                     case 1:     ret.regnum = T1_VARYING; break;
240                     case 2:     ret.regnum = T2_VARYING; break;
241                     case 3:     ret.regnum = T3_VARYING; break;
242                     case 4:     ret.regnum = T4_VARYING; break;
243                     case 5:     ret.regnum = T5_VARYING; break;
244                     case 6:     ret.regnum = T6_VARYING; break;
245                     case 7:     ret.regnum = T7_VARYING; break;
246                     default:
247                         FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
248                         return *reg;
249                 }
250                 return ret;
251             } else {
252                 ret = *reg;
253                 ret.type = BWRITERSPR_TEMP;
254                 switch(reg->regnum) {
255                     case 0:     ret.regnum = T0_REG; break;
256                     case 1:     ret.regnum = T1_REG; break;
257                     case 2:     ret.regnum = T2_REG; break;
258                     case 3:     ret.regnum = T3_REG; break;
259                     default:
260                         FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
261                         return *reg;
262                 }
263                 return ret;
264             }
265
266         /* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
267            to 3.0 ones */
268
269         default: return *reg;
270     }
271 }
272
273 static void asmparser_texcoord(struct asm_parser *This, DWORD mod, DWORD shift,
274                                const struct shader_reg *dst,
275                                const struct src_regs *srcs) {
276     struct instruction *instr;
277
278     if(srcs) {
279         asmparser_message(This, "Line %u: Source registers in texcoord instruction\n", This->line_no);
280         set_parse_status(This, PARSE_ERR);
281         return;
282     }
283
284     instr = alloc_instr(1);
285     if(!instr) {
286         ERR("Error allocating memory for the instruction\n");
287         set_parse_status(This, PARSE_ERR);
288         return;
289     }
290
291     /* texcoord copies the texture coord data into a temporary register-like
292      * readable form. In newer shader models this equals a MOV from v0 to r0,
293      * record it as this.
294      */
295     instr->opcode = BWRITERSIO_MOV;
296     instr->dstmod = mod | BWRITERSPDM_SATURATE; /* texcoord clamps to [0;1] */
297     instr->shift = shift;
298     instr->comptype = 0;
299
300     This->funcs->dstreg(This, instr, dst);
301     /* The src reg needs special care */
302     instr->src[0] = map_oldps_register(dst, TRUE);
303
304     if(!add_instruction(This->shader, instr)) {
305         ERR("Out of memory\n");
306         set_parse_status(This, PARSE_ERR);
307     }
308 }
309
310 static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
311                              const struct shader_reg *dst,
312                              const struct src_regs *srcs) {
313     struct instruction *instr;
314
315     if(!srcs || srcs->count != 1) {
316         asmparser_message(This, "Line %u: Wrong number of source registers in texcrd instruction\n", This->line_no);
317         set_parse_status(This, PARSE_ERR);
318         return;
319     }
320
321     instr = alloc_instr(1);
322     if(!instr) {
323         ERR("Error allocating memory for the instruction\n");
324         set_parse_status(This, PARSE_ERR);
325         return;
326     }
327
328     /* The job of texcrd is done by mov in later shader versions */
329     instr->opcode = BWRITERSIO_MOV;
330     instr->dstmod = mod;
331     instr->shift = shift;
332     instr->comptype = 0;
333
334     This->funcs->dstreg(This, instr, dst);
335     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
336
337     if(!add_instruction(This->shader, instr)) {
338         ERR("Out of memory\n");
339         set_parse_status(This, PARSE_ERR);
340     }
341 }
342
343 static void asmparser_texkill(struct asm_parser *This,
344                               const struct shader_reg *dst) {
345     struct instruction *instr = alloc_instr(0);
346
347     if(!instr) {
348         ERR("Error allocating memory for the instruction\n");
349         set_parse_status(This, PARSE_ERR);
350         return;
351     }
352
353     instr->opcode = BWRITERSIO_TEXKILL;
354     instr->dstmod = 0;
355     instr->shift = 0;
356     instr->comptype = 0;
357
358     /* Do not run the dst register through the normal
359      * register conversion. If used with ps_1_0 to ps_1_3
360      * the texture coordinate from that register is used,
361      * not the temporary register value. In ps_1_4 and
362      * ps_2_0 t0 is always a varying and temporaries can
363      * be used with texkill.
364      */
365     instr->dst = map_oldps_register(dst, TRUE);
366     instr->has_dst = TRUE;
367
368     if(!add_instruction(This->shader, instr)) {
369         ERR("Out of memory\n");
370         set_parse_status(This, PARSE_ERR);
371     }
372 }
373
374 static void asmparser_texhelper(struct asm_parser *This, DWORD mod, DWORD shift,
375                                 const struct shader_reg *dst,
376                                 const struct shader_reg *src0) {
377     struct instruction *instr = alloc_instr(2);
378
379     if(!instr) {
380         ERR("Error allocating memory for the instruction\n");
381         set_parse_status(This, PARSE_ERR);
382         return;
383     }
384
385     instr->opcode = BWRITERSIO_TEX;
386     instr->dstmod = mod;
387     instr->shift = shift;
388     instr->comptype = 0;
389     /* The dest register can be mapped normally to a temporary register */
390     This->funcs->dstreg(This, instr, dst);
391     /* Use the src passed as parameter by the specific instruction handler */
392     instr->src[0] = *src0;
393
394     /* The 2nd source register is the sampler register with the
395      * destination's regnum
396      */
397     ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
398     instr->src[1].type = BWRITERSPR_SAMPLER;
399     instr->src[1].regnum = dst->regnum;
400     instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
401     instr->src[1].srcmod = BWRITERSPSM_NONE;
402     instr->src[1].rel_reg = NULL;
403
404     if(!add_instruction(This->shader, instr)) {
405         ERR("Out of memory\n");
406         set_parse_status(This, PARSE_ERR);
407     }
408 }
409
410 static void asmparser_tex(struct asm_parser *This, DWORD mod, DWORD shift,
411                           const struct shader_reg *dst) {
412     struct shader_reg src;
413
414     /* The first source register is the varying containing the coordinate */
415     src = map_oldps_register(dst, TRUE);
416     asmparser_texhelper(This, mod, shift, dst, &src);
417 }
418
419 static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
420                               const struct shader_reg *dst,
421                               const struct src_regs *srcs) {
422     struct instruction *instr;
423
424     if(!srcs || srcs->count != 1) {
425         asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no);
426         set_parse_status(This, PARSE_ERR);
427         return;
428     }
429
430     instr = alloc_instr(2);
431     if(!instr) {
432         ERR("Error allocating memory for the instruction\n");
433         set_parse_status(This, PARSE_ERR);
434         return;
435     }
436
437     /* This code is recording a texld instruction, not tex. However,
438      * texld borrows the opcode of tex
439      */
440     instr->opcode = BWRITERSIO_TEX;
441     instr->dstmod = mod;
442     instr->shift = shift;
443     instr->comptype = 0;
444
445     This->funcs->dstreg(This, instr, dst);
446     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
447
448     /* The 2nd source register is the sampler register with the
449      * destination's regnum
450      */
451     ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
452     instr->src[1].type = BWRITERSPR_SAMPLER;
453     instr->src[1].regnum = dst->regnum;
454     instr->src[1].u.swizzle = BWRITERVS_NOSWIZZLE;
455     instr->src[1].srcmod = BWRITERSPSM_NONE;
456     instr->src[1].rel_reg = NULL;
457
458     if(!add_instruction(This->shader, instr)) {
459         ERR("Out of memory\n");
460         set_parse_status(This, PARSE_ERR);
461     }
462 }
463
464 static void asmparser_texreg2ar(struct asm_parser *This, DWORD mod, DWORD shift,
465                                 const struct shader_reg *dst,
466                                 const struct shader_reg *src0) {
467     struct shader_reg src;
468
469     src = map_oldps_register(src0, FALSE);
470     /* Supply the correct swizzle */
471     src.u.swizzle = BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X;
472     asmparser_texhelper(This, mod, shift, dst, &src);
473 }
474
475 static void asmparser_texreg2gb(struct asm_parser *This, DWORD mod, DWORD shift,
476                                 const struct shader_reg *dst,
477                                 const struct shader_reg *src0) {
478     struct shader_reg src;
479
480     src = map_oldps_register(src0, FALSE);
481     /* Supply the correct swizzle */
482     src.u.swizzle = BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z;
483     asmparser_texhelper(This, mod, shift, dst, &src);
484 }
485
486 static void asmparser_texreg2rgb(struct asm_parser *This, DWORD mod, DWORD shift,
487                                  const struct shader_reg *dst,
488                                  const struct shader_reg *src0) {
489     struct shader_reg src;
490
491     src = map_oldps_register(src0, FALSE);
492     /* Supply the correct swizzle */
493     src.u.swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z;
494     asmparser_texhelper(This, mod, shift, dst, &src);
495 }
496
497 /* Complex pixel shader 1.3 instructions like texm3x3tex are tricky - the
498  * bytecode writer works instruction by instruction, so we can't properly
499  * convert these from/to equivalent ps_3_0 instructions. Then simply keep using
500  * the ps_1_3 opcodes and just adapt the registers in the common fashion (i.e.
501  * go through asmparser_instr).
502  */
503
504 static void asmparser_instr(struct asm_parser *This, DWORD opcode,
505                             DWORD mod, DWORD shift,
506                             BWRITER_COMPARISON_TYPE comp,
507                             const struct shader_reg *dst,
508                             const struct src_regs *srcs, int expectednsrcs) {
509     struct instruction *instr;
510     unsigned int i;
511     BOOL firstreg = TRUE;
512     unsigned int src_count = srcs ? srcs->count : 0;
513
514     if(!This->shader) return;
515
516     TRACE_(parsed_shader)("%s%s%s%s ", debug_print_opcode(opcode),
517                           debug_print_dstmod(mod),
518                           debug_print_shift(shift),
519                           debug_print_comp(comp));
520     if(dst) {
521         TRACE_(parsed_shader)("%s", debug_print_dstreg(dst));
522         firstreg = FALSE;
523     }
524     for(i = 0; i < src_count; i++) {
525         if(!firstreg) TRACE_(parsed_shader)(", ");
526         else firstreg = FALSE;
527         TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i]));
528     }
529     TRACE_(parsed_shader)("\n");
530
531  /* Check for instructions with different syntaxes in different shader versio
532 ns */
533     switch(opcode) {
534         case BWRITERSIO_SINCOS:
535             /* The syntax changes between vs 2 and the other shader versions */
536             if(This->shader->version == BWRITERVS_VERSION(2, 0) ||
537                This->shader->version == BWRITERVS_VERSION(2, 1)) {
538                 asmparser_sincos(This, mod, shift, dst, srcs);
539                 return;
540             }
541             /* Use the default handling */
542             break;
543         case BWRITERSIO_TEXCOORD:
544             /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
545             if(This->shader->version == BWRITERPS_VERSION(1, 4))
546                 asmparser_texcrd(This, mod, shift, dst, srcs);
547             else asmparser_texcoord(This, mod, shift, dst, srcs);
548             return;
549         case BWRITERSIO_TEX:
550             /* this encodes both the tex PS 1.x instruction and the
551                texld 1.4/2.0+ instruction */
552             if(This->shader->version == BWRITERPS_VERSION(1, 1) ||
553                This->shader->version == BWRITERPS_VERSION(1, 2) ||
554                This->shader->version == BWRITERPS_VERSION(1, 3)) {
555                 asmparser_tex(This, mod, shift, dst);
556                 return;
557             }
558             else if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
559                 asmparser_texld14(This, mod, shift, dst, srcs);
560                 return;
561             }
562             /* else fallback to the standard behavior */
563             break;
564     }
565
566     if(src_count != expectednsrcs) {
567         asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
568         set_parse_status(This, PARSE_ERR);
569         return;
570     }
571
572     /* Handle PS 1.x instructions, "regularizing" them */
573     switch(opcode) {
574         case BWRITERSIO_TEXKILL:
575             asmparser_texkill(This, dst);
576             return;
577         case BWRITERSIO_TEXREG2AR:
578             asmparser_texreg2ar(This, mod, shift, dst, &srcs->reg[0]);
579             return;
580         case BWRITERSIO_TEXREG2GB:
581             asmparser_texreg2gb(This, mod, shift, dst, &srcs->reg[0]);
582             return;
583         case BWRITERSIO_TEXREG2RGB:
584             asmparser_texreg2rgb(This, mod, shift, dst, &srcs->reg[0]);
585             return;
586     }
587
588     instr = alloc_instr(src_count);
589     if(!instr) {
590         ERR("Error allocating memory for the instruction\n");
591         set_parse_status(This, PARSE_ERR);
592         return;
593     }
594
595     instr->opcode = opcode;
596     instr->dstmod = mod;
597     instr->shift = shift;
598     instr->comptype = comp;
599     if(dst) This->funcs->dstreg(This, instr, dst);
600     for(i = 0; i < src_count; i++) {
601         This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
602     }
603
604     if(!add_instruction(This->shader, instr)) {
605         ERR("Out of memory\n");
606         set_parse_status(This, PARSE_ERR);
607     }
608 }
609
610 static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
611     struct shader_reg ret;
612     switch(reg->type) {
613         case BWRITERSPR_RASTOUT:
614             ret = *reg;
615             ret.type = BWRITERSPR_OUTPUT;
616             switch(reg->regnum) {
617                 case BWRITERSRO_POSITION:
618                     ret.regnum = OPOS_REG;
619                     break;
620                 case BWRITERSRO_FOG:
621                     ret.regnum = OFOG_REG;
622                     ret.u.writemask = OFOG_WRITEMASK;
623                     break;
624                 case BWRITERSRO_POINT_SIZE:
625                     ret.regnum = OPTS_REG;
626                     ret.u.writemask = OPTS_WRITEMASK;
627                     break;
628                 default:
629                     FIXME("Unhandled RASTOUT register %u\n", reg->regnum);
630                     return *reg;
631             }
632             return ret;
633
634         case BWRITERSPR_TEXCRDOUT:
635             ret = *reg;
636             ret.type = BWRITERSPR_OUTPUT;
637             switch(reg->regnum) {
638                 case 0: ret.regnum = OT0_REG; break;
639                 case 1: ret.regnum = OT1_REG; break;
640                 case 2: ret.regnum = OT2_REG; break;
641                 case 3: ret.regnum = OT3_REG; break;
642                 case 4: ret.regnum = OT4_REG; break;
643                 case 5: ret.regnum = OT5_REG; break;
644                 case 6: ret.regnum = OT6_REG; break;
645                 case 7: ret.regnum = OT7_REG; break;
646                 default:
647                     FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum);
648                     return *reg;
649             }
650             return ret;
651
652         case BWRITERSPR_ATTROUT:
653             ret = *reg;
654             ret.type = BWRITERSPR_OUTPUT;
655             switch(reg->regnum) {
656                 case 0: ret.regnum = OD0_REG; break;
657                 case 1: ret.regnum = OD1_REG; break;
658                 default:
659                     FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum);
660                     return *reg;
661             }
662             return ret;
663
664         default: return *reg;
665     }
666 }
667
668 /* Checks for unsupported source modifiers in VS (all versions) or
669    PS 2.0 and newer */
670 static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
671     if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG ||
672        srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG ||
673        srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 ||
674        srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ ||
675        srcmod == BWRITERSPSM_DW) {
676         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
677                           This->line_no,
678                           debug_print_srcmod(srcmod));
679         set_parse_status(This, PARSE_ERR);
680     }
681 }
682
683 static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) {
684     if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) {
685         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
686                           This->line_no,
687                           debug_print_srcmod(srcmod));
688         set_parse_status(This, PARSE_ERR);
689     }
690 }
691
692 static void check_loop_swizzle(struct asm_parser *This,
693                                const struct shader_reg *src) {
694     if((src->type == BWRITERSPR_LOOP && src->u.swizzle != BWRITERVS_NOSWIZZLE) ||
695        (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP &&
696         src->rel_reg->u.swizzle != BWRITERVS_NOSWIZZLE)) {
697         asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no);
698         set_parse_status(This, PARSE_ERR);
699     }
700 }
701
702 static void check_shift_dstmod(struct asm_parser *This, DWORD shift) {
703     if(shift != 0) {
704         asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n",
705                           This->line_no);
706         set_parse_status(This, PARSE_ERR);
707     }
708 }
709
710 static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) {
711     if(dstmod == BWRITERSPDM_PARTIALPRECISION ||
712        dstmod == BWRITERSPDM_MSAMPCENTROID) {
713         asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n",
714                           This->line_no,
715                           debug_print_dstmod(dstmod));
716         set_parse_status(This, PARSE_ERR);
717     }
718 }
719
720 struct allowed_reg_type {
721     DWORD type;
722     DWORD count;
723     BOOL reladdr;
724 };
725
726 static BOOL check_reg_type(const struct shader_reg *reg,
727                            const struct allowed_reg_type *allowed) {
728     unsigned int i = 0;
729
730     while(allowed[i].type != ~0U) {
731         if(reg->type == allowed[i].type) {
732             if(reg->rel_reg) {
733                 if(allowed[i].reladdr)
734                     return TRUE; /* The relative addressing register
735                                     can have a negative value, we
736                                     can't check the register index */
737                 return FALSE;
738             }
739             if(reg->regnum < allowed[i].count) return TRUE;
740             return FALSE;
741         }
742         i++;
743     }
744     return FALSE;
745 }
746
747 /* Native assembler doesn't do separate checks for src and dst registers */
748 static const struct allowed_reg_type vs_1_reg_allowed[] = {
749     { BWRITERSPR_TEMP,         12,  FALSE },
750     { BWRITERSPR_INPUT,        16,  FALSE },
751     { BWRITERSPR_CONST,       ~0U,   TRUE },
752     { BWRITERSPR_ADDR,          1,  FALSE },
753     { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */
754     { BWRITERSPR_ATTROUT,       2,  FALSE },
755     { BWRITERSPR_TEXCRDOUT,     8,  FALSE },
756     { ~0U, 0 } /* End tag */
757 };
758
759 /* struct instruction *asmparser_srcreg
760  *
761  * Records a source register in the instruction and does shader version
762  * specific checks and modifications on it
763  *
764  * Parameters:
765  *  This: Shader parser instance
766  *  instr: instruction to store the register in
767  *  num: Number of source register
768  *  src: Pointer to source the register structure. The caller can free
769  *  it afterwards
770  */
771 static void asmparser_srcreg_vs_1(struct asm_parser *This,
772                                   struct instruction *instr, int num,
773                                   const struct shader_reg *src) {
774     struct shader_reg reg;
775
776     if(!check_reg_type(src, vs_1_reg_allowed)) {
777         asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n",
778                           This->line_no,
779                           debug_print_srcreg(src));
780         set_parse_status(This, PARSE_ERR);
781     }
782     check_legacy_srcmod(This, src->srcmod);
783     check_abs_srcmod(This, src->srcmod);
784     reg = map_oldvs_register(src);
785     memcpy(&instr->src[num], &reg, sizeof(reg));
786 }
787
788 static const struct allowed_reg_type vs_2_reg_allowed[] = {
789     { BWRITERSPR_TEMP,      12,  FALSE },
790     { BWRITERSPR_INPUT,     16,  FALSE },
791     { BWRITERSPR_CONST,    ~0U,   TRUE },
792     { BWRITERSPR_ADDR,       1,  FALSE },
793     { BWRITERSPR_CONSTBOOL, 16,  FALSE },
794     { BWRITERSPR_CONSTINT,  16,  FALSE },
795     { BWRITERSPR_LOOP,       1,  FALSE },
796     { BWRITERSPR_LABEL,   2048,  FALSE },
797     { BWRITERSPR_PREDICATE,  1,  FALSE },
798     { BWRITERSPR_RASTOUT,    3,  FALSE }, /* oPos, oFog and oPts */
799     { BWRITERSPR_ATTROUT,    2,  FALSE },
800     { BWRITERSPR_TEXCRDOUT,  8,  FALSE },
801     { ~0U, 0 } /* End tag */
802 };
803
804 static void asmparser_srcreg_vs_2(struct asm_parser *This,
805                                   struct instruction *instr, int num,
806                                   const struct shader_reg *src) {
807     struct shader_reg reg;
808
809     if(!check_reg_type(src, vs_2_reg_allowed)) {
810         asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n",
811                           This->line_no,
812                           debug_print_srcreg(src));
813         set_parse_status(This, PARSE_ERR);
814     }
815     check_loop_swizzle(This, src);
816     check_legacy_srcmod(This, src->srcmod);
817     check_abs_srcmod(This, src->srcmod);
818     reg = map_oldvs_register(src);
819     memcpy(&instr->src[num], &reg, sizeof(reg));
820 }
821
822 static const struct allowed_reg_type vs_3_reg_allowed[] = {
823     { BWRITERSPR_TEMP,         32,  FALSE },
824     { BWRITERSPR_INPUT,        16,   TRUE },
825     { BWRITERSPR_CONST,       ~0U,   TRUE },
826     { BWRITERSPR_ADDR,          1,  FALSE },
827     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
828     { BWRITERSPR_CONSTINT,     16,  FALSE },
829     { BWRITERSPR_LOOP,          1,  FALSE },
830     { BWRITERSPR_LABEL,      2048,  FALSE },
831     { BWRITERSPR_PREDICATE,     1,  FALSE },
832     { BWRITERSPR_SAMPLER,       4,  FALSE },
833     { BWRITERSPR_OUTPUT,       12,   TRUE },
834     { ~0U, 0 } /* End tag */
835 };
836
837 static void asmparser_srcreg_vs_3(struct asm_parser *This,
838                                   struct instruction *instr, int num,
839                                   const struct shader_reg *src) {
840     if(!check_reg_type(src, vs_3_reg_allowed)) {
841         asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n",
842                           This->line_no,
843                           debug_print_srcreg(src));
844         set_parse_status(This, PARSE_ERR);
845     }
846     check_loop_swizzle(This, src);
847     check_legacy_srcmod(This, src->srcmod);
848     memcpy(&instr->src[num], src, sizeof(*src));
849 }
850
851 static const struct allowed_reg_type ps_1_0123_reg_allowed[] = {
852     { BWRITERSPR_CONST,     8,  FALSE },
853     { BWRITERSPR_TEMP,      2,  FALSE },
854     { BWRITERSPR_TEXTURE,   4,  FALSE },
855     { BWRITERSPR_INPUT,     2,  FALSE },
856     { ~0U, 0 } /* End tag */
857 };
858
859 static void asmparser_srcreg_ps_1_0123(struct asm_parser *This,
860                                        struct instruction *instr, int num,
861                                        const struct shader_reg *src) {
862     struct shader_reg reg;
863
864     if(!check_reg_type(src, ps_1_0123_reg_allowed)) {
865         asmparser_message(This, "Line %u: Source register %s not supported in <== PS 1.3\n",
866                           This->line_no,
867                           debug_print_srcreg(src));
868         set_parse_status(This, PARSE_ERR);
869     }
870     check_abs_srcmod(This, src->srcmod);
871     reg = map_oldps_register(src, FALSE);
872     memcpy(&instr->src[num], &reg, sizeof(reg));
873 }
874
875 static const struct allowed_reg_type ps_1_4_reg_allowed[] = {
876     { BWRITERSPR_CONST,     8,  FALSE },
877     { BWRITERSPR_TEMP,      6,  FALSE },
878     { BWRITERSPR_TEXTURE,   6,  FALSE },
879     { BWRITERSPR_INPUT,     2,  FALSE },
880     { ~0U, 0 } /* End tag */
881 };
882
883 static void asmparser_srcreg_ps_1_4(struct asm_parser *This,
884                                     struct instruction *instr, int num,
885                                     const struct shader_reg *src) {
886     struct shader_reg reg;
887
888     if(!check_reg_type(src, ps_1_4_reg_allowed)) {
889         asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\n",
890                           This->line_no,
891                           debug_print_srcreg(src));
892         set_parse_status(This, PARSE_ERR);
893     }
894     check_abs_srcmod(This, src->srcmod);
895     reg = map_oldps_register(src, TRUE);
896     memcpy(&instr->src[num], &reg, sizeof(reg));
897 }
898
899 static const struct allowed_reg_type ps_2_0_reg_allowed[] = {
900     { BWRITERSPR_INPUT,         2,  FALSE },
901     { BWRITERSPR_TEMP,         32,  FALSE },
902     { BWRITERSPR_CONST,        32,  FALSE },
903     { BWRITERSPR_CONSTINT,     16,  FALSE },
904     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
905     { BWRITERSPR_SAMPLER,      16,  FALSE },
906     { BWRITERSPR_TEXTURE,       8,  FALSE },
907     { BWRITERSPR_COLOROUT,      4,  FALSE },
908     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
909     { ~0U, 0 } /* End tag */
910 };
911
912 static void asmparser_srcreg_ps_2(struct asm_parser *This,
913                                   struct instruction *instr, int num,
914                                   const struct shader_reg *src) {
915     struct shader_reg reg;
916
917     if(!check_reg_type(src, ps_2_0_reg_allowed)) {
918         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n",
919                           This->line_no,
920                           debug_print_srcreg(src));
921         set_parse_status(This, PARSE_ERR);
922     }
923     check_legacy_srcmod(This, src->srcmod);
924     check_abs_srcmod(This, src->srcmod);
925     reg = map_oldps_register(src, TRUE);
926     memcpy(&instr->src[num], &reg, sizeof(reg));
927 }
928
929 static const struct allowed_reg_type ps_2_x_reg_allowed[] = {
930     { BWRITERSPR_INPUT,         2,  FALSE },
931     { BWRITERSPR_TEMP,         32,  FALSE },
932     { BWRITERSPR_CONST,        32,  FALSE },
933     { BWRITERSPR_CONSTINT,     16,  FALSE },
934     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
935     { BWRITERSPR_PREDICATE,     1,  FALSE },
936     { BWRITERSPR_SAMPLER,      16,  FALSE },
937     { BWRITERSPR_TEXTURE,       8,  FALSE },
938     { BWRITERSPR_LABEL,      2048,  FALSE },
939     { BWRITERSPR_COLOROUT,      4,  FALSE },
940     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
941     { ~0U, 0 } /* End tag */
942 };
943
944 static void asmparser_srcreg_ps_2_x(struct asm_parser *This,
945                                     struct instruction *instr, int num,
946                                     const struct shader_reg *src) {
947     struct shader_reg reg;
948
949     if(!check_reg_type(src, ps_2_x_reg_allowed)) {
950         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n",
951                           This->line_no,
952                           debug_print_srcreg(src));
953         set_parse_status(This, PARSE_ERR);
954     }
955     check_legacy_srcmod(This, src->srcmod);
956     check_abs_srcmod(This, src->srcmod);
957     reg = map_oldps_register(src, TRUE);
958     memcpy(&instr->src[num], &reg, sizeof(reg));
959 }
960
961 static const struct allowed_reg_type ps_3_reg_allowed[] = {
962     { BWRITERSPR_INPUT,        10,   TRUE },
963     { BWRITERSPR_TEMP,         32,  FALSE },
964     { BWRITERSPR_CONST,       224,  FALSE },
965     { BWRITERSPR_CONSTINT,     16,  FALSE },
966     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
967     { BWRITERSPR_PREDICATE,     1,  FALSE },
968     { BWRITERSPR_SAMPLER,      16,  FALSE },
969     { BWRITERSPR_MISCTYPE,      2,  FALSE }, /* vPos and vFace */
970     { BWRITERSPR_LOOP,          1,  FALSE },
971     { BWRITERSPR_LABEL,      2048,  FALSE },
972     { BWRITERSPR_COLOROUT,      4,  FALSE },
973     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
974     { ~0U, 0 } /* End tag */
975 };
976
977 static void asmparser_srcreg_ps_3(struct asm_parser *This,
978                                   struct instruction *instr, int num,
979                                   const struct shader_reg *src) {
980     if(!check_reg_type(src, ps_3_reg_allowed)) {
981         asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n",
982                           This->line_no,
983                           debug_print_srcreg(src));
984         set_parse_status(This, PARSE_ERR);
985     }
986     check_loop_swizzle(This, src);
987     check_legacy_srcmod(This, src->srcmod);
988     memcpy(&instr->src[num], src, sizeof(*src));
989 }
990
991 static void asmparser_dstreg_vs_1(struct asm_parser *This,
992                                   struct instruction *instr,
993                                   const struct shader_reg *dst) {
994     struct shader_reg reg;
995
996     if(!check_reg_type(dst, vs_1_reg_allowed)) {
997         asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n",
998                           This->line_no,
999                           debug_print_dstreg(dst));
1000         set_parse_status(This, PARSE_ERR);
1001     }
1002     check_ps_dstmod(This, instr->dstmod);
1003     check_shift_dstmod(This, instr->shift);
1004     reg = map_oldvs_register(dst);
1005     memcpy(&instr->dst, &reg, sizeof(reg));
1006     instr->has_dst = TRUE;
1007 }
1008
1009 static void asmparser_dstreg_vs_2(struct asm_parser *This,
1010                                   struct instruction *instr,
1011                                   const struct shader_reg *dst) {
1012     struct shader_reg reg;
1013
1014     if(!check_reg_type(dst, vs_2_reg_allowed)) {
1015         asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n",
1016                           This->line_no,
1017                           debug_print_dstreg(dst));
1018         set_parse_status(This, PARSE_ERR);
1019     }
1020     check_ps_dstmod(This, instr->dstmod);
1021     check_shift_dstmod(This, instr->shift);
1022     reg = map_oldvs_register(dst);
1023     memcpy(&instr->dst, &reg, sizeof(reg));
1024     instr->has_dst = TRUE;
1025 }
1026
1027 static void asmparser_dstreg_vs_3(struct asm_parser *This,
1028                                   struct instruction *instr,
1029                                   const struct shader_reg *dst) {
1030     if(!check_reg_type(dst, vs_3_reg_allowed)) {
1031         asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n",
1032                           This->line_no,
1033                           debug_print_dstreg(dst));
1034         set_parse_status(This, PARSE_ERR);
1035     }
1036     check_ps_dstmod(This, instr->dstmod);
1037     check_shift_dstmod(This, instr->shift);
1038     memcpy(&instr->dst, dst, sizeof(*dst));
1039     instr->has_dst = TRUE;
1040 }
1041
1042 static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
1043                                        struct instruction *instr,
1044                                        const struct shader_reg *dst) {
1045     struct shader_reg reg;
1046
1047     if(!check_reg_type(dst, ps_1_0123_reg_allowed)) {
1048         asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
1049                           This->line_no,
1050                           debug_print_dstreg(dst));
1051         set_parse_status(This, PARSE_ERR);
1052     }
1053     reg = map_oldps_register(dst, FALSE);
1054     memcpy(&instr->dst, &reg, sizeof(reg));
1055     instr->has_dst = TRUE;
1056 }
1057
1058 static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
1059                                     struct instruction *instr,
1060                                     const struct shader_reg *dst) {
1061     struct shader_reg reg;
1062
1063     if(!check_reg_type(dst, ps_1_4_reg_allowed)) {
1064         asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
1065                           This->line_no,
1066                           debug_print_dstreg(dst));
1067         set_parse_status(This, PARSE_ERR);
1068     }
1069     reg = map_oldps_register(dst, TRUE);
1070     memcpy(&instr->dst, &reg, sizeof(reg));
1071     instr->has_dst = TRUE;
1072 }
1073
1074 static void asmparser_dstreg_ps_2(struct asm_parser *This,
1075                                   struct instruction *instr,
1076                                   const struct shader_reg *dst) {
1077     struct shader_reg reg;
1078
1079     if(!check_reg_type(dst, ps_2_0_reg_allowed)) {
1080         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n",
1081                           This->line_no,
1082                           debug_print_dstreg(dst));
1083         set_parse_status(This, PARSE_ERR);
1084     }
1085     check_shift_dstmod(This, instr->shift);
1086     reg = map_oldps_register(dst, TRUE);
1087     memcpy(&instr->dst, &reg, sizeof(reg));
1088     instr->has_dst = TRUE;
1089 }
1090
1091 static void asmparser_dstreg_ps_2_x(struct asm_parser *This,
1092                                     struct instruction *instr,
1093                                     const struct shader_reg *dst) {
1094     struct shader_reg reg;
1095
1096     if(!check_reg_type(dst, ps_2_x_reg_allowed)) {
1097         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n",
1098                           This->line_no,
1099                           debug_print_dstreg(dst));
1100         set_parse_status(This, PARSE_ERR);
1101     }
1102     check_shift_dstmod(This, instr->shift);
1103     reg = map_oldps_register(dst, TRUE);
1104     memcpy(&instr->dst, &reg, sizeof(reg));
1105     instr->has_dst = TRUE;
1106 }
1107
1108 static void asmparser_dstreg_ps_3(struct asm_parser *This,
1109                                   struct instruction *instr,
1110                                   const struct shader_reg *dst) {
1111     if(!check_reg_type(dst, ps_3_reg_allowed)) {
1112         asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n",
1113                           This->line_no,
1114                           debug_print_dstreg(dst));
1115         set_parse_status(This, PARSE_ERR);
1116     }
1117     check_shift_dstmod(This, instr->shift);
1118     memcpy(&instr->dst, dst, sizeof(*dst));
1119     instr->has_dst = TRUE;
1120 }
1121
1122 static void asmparser_predicate_supported(struct asm_parser *This,
1123                                           const struct shader_reg *predicate) {
1124     /* this sets the predicate of the last instruction added to the shader */
1125     if(!This->shader) return;
1126     if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n");
1127     This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE;
1128     memcpy(&This->shader->instr[This->shader->num_instrs - 1]->predicate, predicate, sizeof(*predicate));
1129 }
1130
1131 static void asmparser_predicate_unsupported(struct asm_parser *This,
1132                                             const struct shader_reg *predicate) {
1133     asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
1134     set_parse_status(This, PARSE_ERR);
1135 }
1136
1137 static void asmparser_coissue_supported(struct asm_parser *This) {
1138     /* this sets the coissue flag of the last instruction added to the shader */
1139     if(!This->shader) return;
1140     if(This->shader->num_instrs == 0){
1141         asmparser_message(This, "Line %u: Coissue flag on the first shader instruction\n", This->line_no);
1142         set_parse_status(This, PARSE_ERR);
1143     }
1144     This->shader->instr[This->shader->num_instrs-1]->coissue = TRUE;
1145 }
1146
1147 static void asmparser_coissue_unsupported(struct asm_parser *This) {
1148     asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
1149     set_parse_status(This, PARSE_ERR);
1150 }
1151
1152 static const struct asmparser_backend parser_vs_1 = {
1153     asmparser_constF,
1154     asmparser_constI,
1155     asmparser_constB,
1156
1157     asmparser_dstreg_vs_1,
1158     asmparser_srcreg_vs_1,
1159
1160     asmparser_predicate_unsupported,
1161     asmparser_coissue_unsupported,
1162
1163     asmparser_dcl_output_unsupported,
1164     asmparser_dcl_input,
1165     asmparser_dcl_sampler_unsupported,
1166
1167     asmparser_end,
1168
1169     asmparser_instr,
1170 };
1171
1172 static const struct asmparser_backend parser_vs_2 = {
1173     asmparser_constF,
1174     asmparser_constI,
1175     asmparser_constB,
1176
1177     asmparser_dstreg_vs_2,
1178     asmparser_srcreg_vs_2,
1179
1180     asmparser_predicate_supported,
1181     asmparser_coissue_unsupported,
1182
1183     asmparser_dcl_output_unsupported,
1184     asmparser_dcl_input,
1185     asmparser_dcl_sampler_unsupported,
1186
1187     asmparser_end,
1188
1189     asmparser_instr,
1190 };
1191
1192 static const struct asmparser_backend parser_vs_3 = {
1193     asmparser_constF,
1194     asmparser_constI,
1195     asmparser_constB,
1196
1197     asmparser_dstreg_vs_3,
1198     asmparser_srcreg_vs_3,
1199
1200     asmparser_predicate_supported,
1201     asmparser_coissue_unsupported,
1202
1203     asmparser_dcl_output,
1204     asmparser_dcl_input,
1205     asmparser_dcl_sampler,
1206
1207     asmparser_end,
1208
1209     asmparser_instr,
1210 };
1211
1212 static const struct asmparser_backend parser_ps_1_0123 = {
1213     asmparser_constF,
1214     asmparser_constI,
1215     asmparser_constB,
1216
1217     asmparser_dstreg_ps_1_0123,
1218     asmparser_srcreg_ps_1_0123,
1219
1220     asmparser_predicate_unsupported,
1221     asmparser_coissue_supported,
1222
1223     asmparser_dcl_output_unsupported,
1224     asmparser_dcl_input_unsupported,
1225     asmparser_dcl_sampler_unsupported,
1226
1227     asmparser_end,
1228
1229     asmparser_instr,
1230 };
1231
1232 static const struct asmparser_backend parser_ps_1_4 = {
1233     asmparser_constF,
1234     asmparser_constI,
1235     asmparser_constB,
1236
1237     asmparser_dstreg_ps_1_4,
1238     asmparser_srcreg_ps_1_4,
1239
1240     asmparser_predicate_unsupported,
1241     asmparser_coissue_supported,
1242
1243     asmparser_dcl_output_unsupported,
1244     asmparser_dcl_input_unsupported,
1245     asmparser_dcl_sampler_unsupported,
1246
1247     asmparser_end,
1248
1249     asmparser_instr,
1250 };
1251
1252 static const struct asmparser_backend parser_ps_2 = {
1253     asmparser_constF,
1254     asmparser_constI,
1255     asmparser_constB,
1256
1257     asmparser_dstreg_ps_2,
1258     asmparser_srcreg_ps_2,
1259
1260     asmparser_predicate_unsupported,
1261     asmparser_coissue_unsupported,
1262
1263     asmparser_dcl_output_unsupported,
1264     asmparser_dcl_input_ps_2,
1265     asmparser_dcl_sampler,
1266
1267     asmparser_end,
1268
1269     asmparser_instr,
1270 };
1271
1272 static const struct asmparser_backend parser_ps_2_x = {
1273     asmparser_constF,
1274     asmparser_constI,
1275     asmparser_constB,
1276
1277     asmparser_dstreg_ps_2_x,
1278     asmparser_srcreg_ps_2_x,
1279
1280     asmparser_predicate_supported,
1281     asmparser_coissue_unsupported,
1282
1283     asmparser_dcl_output_unsupported,
1284     asmparser_dcl_input_ps_2,
1285     asmparser_dcl_sampler,
1286
1287     asmparser_end,
1288
1289     asmparser_instr,
1290 };
1291
1292 static const struct asmparser_backend parser_ps_3 = {
1293     asmparser_constF,
1294     asmparser_constI,
1295     asmparser_constB,
1296
1297     asmparser_dstreg_ps_3,
1298     asmparser_srcreg_ps_3,
1299
1300     asmparser_predicate_supported,
1301     asmparser_coissue_unsupported,
1302
1303     asmparser_dcl_output_unsupported,
1304     asmparser_dcl_input,
1305     asmparser_dcl_sampler,
1306
1307     asmparser_end,
1308
1309     asmparser_instr,
1310 };
1311
1312 static void gen_oldvs_output(struct bwriter_shader *shader) {
1313     record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1314     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1315     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1316     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1317     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1318     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1319     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1320     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1321     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1322     record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, 0, TRUE, OFOG_REG, OFOG_WRITEMASK, TRUE);
1323     record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, 0, TRUE, OPTS_REG, OPTS_WRITEMASK, TRUE);
1324     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1325     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
1326 }
1327
1328 static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
1329     switch(texcoords) {
1330         case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1331         case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1332         case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1333         case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1334         case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1335         case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1336         case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1337         case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1338     };
1339     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1340     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
1341 }
1342
1343 void create_vs10_parser(struct asm_parser *ret) {
1344     TRACE_(parsed_shader)("vs_1_0\n");
1345
1346     ret->shader = asm_alloc(sizeof(*ret->shader));
1347     if(!ret->shader) {
1348         ERR("Failed to allocate memory for the shader\n");
1349         set_parse_status(ret, PARSE_ERR);
1350         return;
1351     }
1352
1353     ret->shader->type = ST_VERTEX;
1354     ret->shader->version = BWRITERVS_VERSION(1, 0);
1355     ret->funcs = &parser_vs_1;
1356     gen_oldvs_output(ret->shader);
1357 }
1358
1359 void create_vs11_parser(struct asm_parser *ret) {
1360     TRACE_(parsed_shader)("vs_1_1\n");
1361
1362     ret->shader = asm_alloc(sizeof(*ret->shader));
1363     if(!ret->shader) {
1364         ERR("Failed to allocate memory for the shader\n");
1365         set_parse_status(ret, PARSE_ERR);
1366         return;
1367     }
1368
1369     ret->shader->type = ST_VERTEX;
1370     ret->shader->version = BWRITERVS_VERSION(1, 1);
1371     ret->funcs = &parser_vs_1;
1372     gen_oldvs_output(ret->shader);
1373 }
1374
1375 void create_vs20_parser(struct asm_parser *ret) {
1376     TRACE_(parsed_shader)("vs_2_0\n");
1377
1378     ret->shader = asm_alloc(sizeof(*ret->shader));
1379     if(!ret->shader) {
1380         ERR("Failed to allocate memory for the shader\n");
1381         set_parse_status(ret, PARSE_ERR);
1382         return;
1383     }
1384
1385     ret->shader->type = ST_VERTEX;
1386     ret->shader->version = BWRITERVS_VERSION(2, 0);
1387     ret->funcs = &parser_vs_2;
1388     gen_oldvs_output(ret->shader);
1389 }
1390
1391 void create_vs2x_parser(struct asm_parser *ret) {
1392     TRACE_(parsed_shader)("vs_2_x\n");
1393
1394     ret->shader = asm_alloc(sizeof(*ret->shader));
1395     if(!ret->shader) {
1396         ERR("Failed to allocate memory for the shader\n");
1397         set_parse_status(ret, PARSE_ERR);
1398         return;
1399     }
1400
1401     ret->shader->type = ST_VERTEX;
1402     ret->shader->version = BWRITERVS_VERSION(2, 1);
1403     ret->funcs = &parser_vs_2;
1404     gen_oldvs_output(ret->shader);
1405 }
1406
1407 void create_vs30_parser(struct asm_parser *ret) {
1408     TRACE_(parsed_shader)("vs_3_0\n");
1409
1410     ret->shader = asm_alloc(sizeof(*ret->shader));
1411     if(!ret->shader) {
1412         ERR("Failed to allocate memory for the shader\n");
1413         set_parse_status(ret, PARSE_ERR);
1414         return;
1415     }
1416
1417     ret->shader->type = ST_VERTEX;
1418     ret->shader->version = BWRITERVS_VERSION(3, 0);
1419     ret->funcs = &parser_vs_3;
1420 }
1421
1422 void create_ps10_parser(struct asm_parser *ret) {
1423     TRACE_(parsed_shader)("ps_1_0\n");
1424
1425     ret->shader = asm_alloc(sizeof(*ret->shader));
1426     if(!ret->shader) {
1427         ERR("Failed to allocate memory for the shader\n");
1428         set_parse_status(ret, PARSE_ERR);
1429         return;
1430     }
1431
1432     ret->shader->type = ST_PIXEL;
1433     ret->shader->version = BWRITERPS_VERSION(1, 0);
1434     ret->funcs = &parser_ps_1_0123;
1435     gen_oldps_input(ret->shader, 4);
1436 }
1437
1438 void create_ps11_parser(struct asm_parser *ret) {
1439     TRACE_(parsed_shader)("ps_1_1\n");
1440
1441     ret->shader = asm_alloc(sizeof(*ret->shader));
1442     if(!ret->shader) {
1443         ERR("Failed to allocate memory for the shader\n");
1444         set_parse_status(ret, PARSE_ERR);
1445         return;
1446     }
1447
1448     ret->shader->type = ST_PIXEL;
1449     ret->shader->version = BWRITERPS_VERSION(1, 1);
1450     ret->funcs = &parser_ps_1_0123;
1451     gen_oldps_input(ret->shader, 4);
1452 }
1453
1454 void create_ps12_parser(struct asm_parser *ret) {
1455     TRACE_(parsed_shader)("ps_1_2\n");
1456
1457     ret->shader = asm_alloc(sizeof(*ret->shader));
1458     if(!ret->shader) {
1459         ERR("Failed to allocate memory for the shader\n");
1460         set_parse_status(ret, PARSE_ERR);
1461         return;
1462     }
1463
1464     ret->shader->type = ST_PIXEL;
1465     ret->shader->version = BWRITERPS_VERSION(1, 2);
1466     ret->funcs = &parser_ps_1_0123;
1467     gen_oldps_input(ret->shader, 4);
1468 }
1469
1470 void create_ps13_parser(struct asm_parser *ret) {
1471     TRACE_(parsed_shader)("ps_1_3\n");
1472
1473     ret->shader = asm_alloc(sizeof(*ret->shader));
1474     if(!ret->shader) {
1475         ERR("Failed to allocate memory for the shader\n");
1476         set_parse_status(ret, PARSE_ERR);
1477         return;
1478     }
1479
1480     ret->shader->type = ST_PIXEL;
1481     ret->shader->version = BWRITERPS_VERSION(1, 3);
1482     ret->funcs = &parser_ps_1_0123;
1483     gen_oldps_input(ret->shader, 4);
1484 }
1485
1486 void create_ps14_parser(struct asm_parser *ret) {
1487     TRACE_(parsed_shader)("ps_1_4\n");
1488
1489     ret->shader = asm_alloc(sizeof(*ret->shader));
1490     if(!ret->shader) {
1491         ERR("Failed to allocate memory for the shader\n");
1492         set_parse_status(ret, PARSE_ERR);
1493         return;
1494     }
1495
1496     ret->shader->type = ST_PIXEL;
1497     ret->shader->version = BWRITERPS_VERSION(1, 4);
1498     ret->funcs = &parser_ps_1_4;
1499     gen_oldps_input(ret->shader, 6);
1500 }
1501
1502 void create_ps20_parser(struct asm_parser *ret) {
1503     TRACE_(parsed_shader)("ps_2_0\n");
1504
1505     ret->shader = asm_alloc(sizeof(*ret->shader));
1506     if(!ret->shader) {
1507         ERR("Failed to allocate memory for the shader\n");
1508         set_parse_status(ret, PARSE_ERR);
1509         return;
1510     }
1511
1512     ret->shader->type = ST_PIXEL;
1513     ret->shader->version = BWRITERPS_VERSION(2, 0);
1514     ret->funcs = &parser_ps_2;
1515     gen_oldps_input(ret->shader, 8);
1516 }
1517
1518 void create_ps2x_parser(struct asm_parser *ret) {
1519     TRACE_(parsed_shader)("ps_2_x\n");
1520
1521     ret->shader = asm_alloc(sizeof(*ret->shader));
1522     if(!ret->shader) {
1523         ERR("Failed to allocate memory for the shader\n");
1524         set_parse_status(ret, PARSE_ERR);
1525         return;
1526     }
1527
1528     ret->shader->type = ST_PIXEL;
1529     ret->shader->version = BWRITERPS_VERSION(2, 1);
1530     ret->funcs = &parser_ps_2_x;
1531     gen_oldps_input(ret->shader, 8);
1532 }
1533
1534 void create_ps30_parser(struct asm_parser *ret) {
1535     TRACE_(parsed_shader)("ps_3_0\n");
1536
1537     ret->shader = asm_alloc(sizeof(*ret->shader));
1538     if(!ret->shader) {
1539         ERR("Failed to allocate memory for the shader\n");
1540         set_parse_status(ret, PARSE_ERR);
1541         return;
1542     }
1543
1544     ret->shader->type = ST_PIXEL;
1545     ret->shader->version = BWRITERPS_VERSION(3, 0);
1546     ret->funcs = &parser_ps_3;
1547 }