d3dx9: Check register type in dcl input instruction.
[wine] / dlls / d3dx9_36 / 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 "d3dx9_36_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->writemask, FALSE)) {
114         ERR("Out of memory\n");
115         set_parse_status(This, PARSE_ERR);
116     }
117 }
118
119 static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num,
120                                 DWORD mod, const struct shader_reg *reg) {
121     struct instruction instr;
122
123     if(!This->shader) return;
124     if(mod != 0 &&
125        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
126         (mod != BWRITERSPDM_MSAMPCENTROID &&
127          mod != BWRITERSPDM_PARTIALPRECISION))) {
128         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
129         set_parse_status(This, PARSE_ERR);
130         return;
131     }
132
133     /* Check register type and modifiers */
134     instr.dstmod = mod;
135     instr.shift = 0;
136     This->funcs->dstreg(This, &instr, reg);
137
138     if(!record_declaration(This->shader, usage, num, mod, FALSE, reg->regnum, reg->writemask, FALSE)) {
139         ERR("Out of memory\n");
140         set_parse_status(This, PARSE_ERR);
141     }
142 }
143
144 static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD num,
145                                      DWORD mod, const struct shader_reg *reg) {
146     struct instruction instr;
147
148     if(!This->shader) return;
149     if(usage != 0) {
150         asmparser_message(This, "Line %u: Unsupported usage in dcl instruction\n", This->line_no);
151         set_parse_status(This, PARSE_ERR);
152         return;
153     }
154     instr.dstmod = mod;
155     instr.shift = 0;
156     This->funcs->dstreg(This, &instr, reg);
157     if(!record_declaration(This->shader, usage, num, mod, FALSE, instr.dst.regnum, instr.dst.writemask, FALSE)) {
158         ERR("Out of memory\n");
159         set_parse_status(This, PARSE_ERR);
160     }
161 }
162
163 static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype,
164                                   DWORD mod, DWORD regnum,
165                                   unsigned int line_no) {
166     if(!This->shader) return;
167     if(mod != 0 &&
168        (This->shader->version != BWRITERPS_VERSION(3, 0) ||
169         (mod != BWRITERSPDM_MSAMPCENTROID &&
170          mod != BWRITERSPDM_PARTIALPRECISION))) {
171         asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no);
172         set_parse_status(This, PARSE_ERR);
173         return;
174     }
175     if(!record_sampler(This->shader, samptype, mod, regnum)) {
176         ERR("Out of memory\n");
177         set_parse_status(This, PARSE_ERR);
178     }
179 }
180
181 static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
182                              const struct shader_reg *dst,
183                              const struct src_regs *srcs) {
184     struct instruction *instr;
185
186     if(!srcs || srcs->count != 3) {
187         asmparser_message(This, "Line %u: sincos (vs 2) has an incorrect number of source registers\n", This->line_no);
188         set_parse_status(This, PARSE_ERR);
189         return;
190     }
191
192     instr = alloc_instr(3);
193     if(!instr) {
194         ERR("Error allocating memory for the instruction\n");
195         set_parse_status(This, PARSE_ERR);
196         return;
197     }
198
199     instr->opcode = BWRITERSIO_SINCOS;
200     instr->dstmod = mod;
201     instr->shift = shift;
202     instr->comptype = 0;
203
204     This->funcs->dstreg(This, instr, dst);
205     This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
206     This->funcs->srcreg(This, instr, 1, &srcs->reg[1]);
207     This->funcs->srcreg(This, instr, 2, &srcs->reg[2]);
208
209     if(!add_instruction(This->shader, instr)) {
210         ERR("Out of memory\n");
211         set_parse_status(This, PARSE_ERR);
212     }
213 }
214
215 static void asmparser_instr(struct asm_parser *This, DWORD opcode,
216                             DWORD mod, DWORD shift,
217                             BWRITER_COMPARISON_TYPE comp,
218                             const struct shader_reg *dst,
219                             const struct src_regs *srcs, int expectednsrcs) {
220     struct instruction *instr;
221     unsigned int i;
222     BOOL firstreg = TRUE;
223     unsigned int src_count = srcs ? srcs->count : 0;
224
225     if(!This->shader) return;
226
227     TRACE_(parsed_shader)("%s%s%s ", debug_print_opcode(opcode),
228                           debug_print_dstmod(mod),
229                           debug_print_comp(comp));
230     if(dst) {
231         TRACE_(parsed_shader)("%s", debug_print_dstreg(dst, This->shader->type));
232         firstreg = FALSE;
233     }
234     for(i = 0; i < src_count; i++) {
235         if(!firstreg) TRACE_(parsed_shader)(", ");
236         else firstreg = FALSE;
237         TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i],
238                                                        This->shader->type));
239     }
240     TRACE_(parsed_shader)("\n");
241
242  /* Check for instructions with different syntaxes in different shader versio
243 ns */
244     switch(opcode) {
245         case BWRITERSIO_SINCOS:
246             /* The syntax changes between vs 2 and the other shader versions */
247             if(This->shader->version == BWRITERVS_VERSION(2, 0) ||
248                This->shader->version == BWRITERVS_VERSION(2, 1)) {
249                 asmparser_sincos(This, mod, shift, dst, srcs);
250                 return;
251             }
252             /* Use the default handling */
253             break;
254     }
255
256     if(src_count != expectednsrcs) {
257         asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
258         set_parse_status(This, PARSE_ERR);
259         return;
260     }
261
262     instr = alloc_instr(src_count);
263     if(!instr) {
264         ERR("Error allocating memory for the instruction\n");
265         set_parse_status(This, PARSE_ERR);
266         return;
267     }
268
269     instr->opcode = opcode;
270     instr->dstmod = mod;
271     instr->shift = shift;
272     instr->comptype = comp;
273     if(dst) This->funcs->dstreg(This, instr, dst);
274     for(i = 0; i < src_count; i++) {
275         This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
276     }
277
278     if(!add_instruction(This->shader, instr)) {
279         ERR("Out of memory\n");
280         set_parse_status(This, PARSE_ERR);
281     }
282 }
283
284 static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
285     struct shader_reg ret;
286     switch(reg->type) {
287         case BWRITERSPR_RASTOUT:
288             ret = *reg;
289             ret.type = BWRITERSPR_OUTPUT;
290             switch(reg->regnum) {
291                 case BWRITERSRO_POSITION:
292                     ret.regnum = OPOS_REG;
293                     break;
294                 case BWRITERSRO_FOG:
295                     ret.regnum = OFOG_REG;
296                     ret.writemask = OFOG_WRITEMASK;
297                     break;
298                 case BWRITERSRO_POINT_SIZE:
299                     ret.regnum = OPTS_REG;
300                     ret.writemask = OPTS_WRITEMASK;
301                     break;
302                 default:
303                     FIXME("Unhandled RASTOUT register %u\n", reg->regnum);
304                     return *reg;
305             }
306             return ret;
307
308         case BWRITERSPR_TEXCRDOUT:
309             ret = *reg;
310             ret.type = BWRITERSPR_OUTPUT;
311             switch(reg->regnum) {
312                 case 0: ret.regnum = OT0_REG; break;
313                 case 1: ret.regnum = OT1_REG; break;
314                 case 2: ret.regnum = OT2_REG; break;
315                 case 3: ret.regnum = OT3_REG; break;
316                 case 4: ret.regnum = OT4_REG; break;
317                 case 5: ret.regnum = OT5_REG; break;
318                 case 6: ret.regnum = OT6_REG; break;
319                 case 7: ret.regnum = OT7_REG; break;
320                 default:
321                     FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum);
322                     return *reg;
323             }
324             return ret;
325
326         case BWRITERSPR_ATTROUT:
327             ret = *reg;
328             ret.type = BWRITERSPR_OUTPUT;
329             switch(reg->regnum) {
330                 case 0: ret.regnum = OD0_REG; break;
331                 case 1: ret.regnum = OD1_REG; break;
332                 default:
333                     FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum);
334                     return *reg;
335             }
336             return ret;
337
338         default: return *reg;
339     }
340 }
341
342 static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
343     struct shader_reg ret;
344     switch(reg->type) {
345         case BWRITERSPR_TEXTURE:
346             if(tex_varying) {
347                 ret = *reg;
348                 ret.type = BWRITERSPR_INPUT;
349                 switch(reg->regnum) {
350                     case 0:     ret.regnum = T0_VARYING; break;
351                     case 1:     ret.regnum = T1_VARYING; break;
352                     case 2:     ret.regnum = T2_VARYING; break;
353                     case 3:     ret.regnum = T3_VARYING; break;
354                     case 4:     ret.regnum = T4_VARYING; break;
355                     case 5:     ret.regnum = T5_VARYING; break;
356                     case 6:     ret.regnum = T6_VARYING; break;
357                     case 7:     ret.regnum = T7_VARYING; break;
358                     default:
359                         FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
360                         return *reg;
361                 }
362                 return ret;
363             } else {
364                 FIXME("TODO: ps_1_x texture register mapping\n");
365                 return *reg;
366             }
367
368         /* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
369            to 3.0 ones */
370
371         default: return *reg;
372     }
373 }
374
375 /* Checks for unsupported source modifiers in VS (all versions) or
376    PS 2.0 and newer */
377 static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
378     if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG ||
379        srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG ||
380        srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 ||
381        srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ ||
382        srcmod == BWRITERSPSM_DW) {
383         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
384                           This->line_no,
385                           debug_print_srcmod(srcmod));
386         set_parse_status(This, PARSE_ERR);
387     }
388 }
389
390 static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) {
391     if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) {
392         asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
393                           This->line_no,
394                           debug_print_srcmod(srcmod));
395         set_parse_status(This, PARSE_ERR);
396     }
397 }
398
399 static void check_loop_swizzle(struct asm_parser *This,
400                                const struct shader_reg *src) {
401     if((src->type == BWRITERSPR_LOOP && src->swizzle != BWRITERVS_NOSWIZZLE) ||
402        (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP &&
403         src->rel_reg->swizzle != BWRITERVS_NOSWIZZLE)) {
404         asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no);
405         set_parse_status(This, PARSE_ERR);
406     }
407 }
408
409 static void check_shift_dstmod(struct asm_parser *This, DWORD shift) {
410     if(shift != 0) {
411         asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n",
412                           This->line_no);
413         set_parse_status(This, PARSE_ERR);
414     }
415 }
416
417 static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) {
418     if(dstmod == BWRITERSPDM_PARTIALPRECISION ||
419        dstmod == BWRITERSPDM_MSAMPCENTROID) {
420         asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n",
421                           This->line_no,
422                           debug_print_dstmod(dstmod));
423         set_parse_status(This, PARSE_ERR);
424     }
425 }
426
427 struct allowed_reg_type {
428     DWORD type;
429     DWORD count;
430     BOOL reladdr;
431 };
432
433 static BOOL check_reg_type(const struct shader_reg *reg,
434                            const struct allowed_reg_type *allowed) {
435     unsigned int i = 0;
436
437     while(allowed[i].type != ~0U) {
438         if(reg->type == allowed[i].type) {
439             if(reg->rel_reg) {
440                 if(allowed[i].reladdr)
441                     return TRUE; /* The relative addressing register
442                                     can have a negative value, we
443                                     can't check the register index */
444                 return FALSE;
445             }
446             if(reg->regnum < allowed[i].count) return TRUE;
447             return FALSE;
448         }
449         i++;
450     }
451     return FALSE;
452 }
453
454 /* Native assembler doesn't do separate checks for src and dst registers */
455 static const struct allowed_reg_type vs_1_reg_allowed[] = {
456     { BWRITERSPR_TEMP,         12,  FALSE },
457     { BWRITERSPR_INPUT,        16,  FALSE },
458     { BWRITERSPR_CONST,       ~0U,   TRUE },
459     { BWRITERSPR_ADDR,          1,  FALSE },
460     { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */
461     { BWRITERSPR_ATTROUT,       2,  FALSE },
462     { BWRITERSPR_TEXCRDOUT,     8,  FALSE },
463     { ~0U, 0 } /* End tag */
464 };
465
466 /* struct instruction *asmparser_srcreg
467  *
468  * Records a source register in the instruction and does shader version
469  * specific checks and modifications on it
470  *
471  * Parameters:
472  *  This: Shader parser instance
473  *  instr: instruction to store the register in
474  *  num: Number of source register
475  *  src: Pointer to source the register structure. The caller can free
476  *  it afterwards
477  */
478 static void asmparser_srcreg_vs_1(struct asm_parser *This,
479                                   struct instruction *instr, int num,
480                                   const struct shader_reg *src) {
481     struct shader_reg reg;
482
483     if(!check_reg_type(src, vs_1_reg_allowed)) {
484         asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n",
485                           This->line_no,
486                           debug_print_srcreg(src, ST_VERTEX));
487         set_parse_status(This, PARSE_ERR);
488     }
489     check_legacy_srcmod(This, src->srcmod);
490     check_abs_srcmod(This, src->srcmod);
491     reg = map_oldvs_register(src);
492     memcpy(&instr->src[num], &reg, sizeof(reg));
493 }
494
495 static const struct allowed_reg_type vs_2_reg_allowed[] = {
496     { BWRITERSPR_TEMP,      12,  FALSE },
497     { BWRITERSPR_INPUT,     16,  FALSE },
498     { BWRITERSPR_CONST,    ~0U,   TRUE },
499     { BWRITERSPR_ADDR,       1,  FALSE },
500     { BWRITERSPR_CONSTBOOL, 16,  FALSE },
501     { BWRITERSPR_CONSTINT,  16,  FALSE },
502     { BWRITERSPR_LOOP,       1,  FALSE },
503     { BWRITERSPR_LABEL,   2048,  FALSE },
504     { BWRITERSPR_PREDICATE,  1,  FALSE },
505     { BWRITERSPR_RASTOUT,    3,  FALSE }, /* oPos, oFog and oPts */
506     { BWRITERSPR_ATTROUT,    2,  FALSE },
507     { BWRITERSPR_TEXCRDOUT,  8,  FALSE },
508     { ~0U, 0 } /* End tag */
509 };
510
511 static void asmparser_srcreg_vs_2(struct asm_parser *This,
512                                   struct instruction *instr, int num,
513                                   const struct shader_reg *src) {
514     struct shader_reg reg;
515
516     if(!check_reg_type(src, vs_2_reg_allowed)) {
517         asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n",
518                           This->line_no,
519                           debug_print_srcreg(src, ST_VERTEX));
520         set_parse_status(This, PARSE_ERR);
521     }
522     check_loop_swizzle(This, src);
523     check_legacy_srcmod(This, src->srcmod);
524     check_abs_srcmod(This, src->srcmod);
525     reg = map_oldvs_register(src);
526     memcpy(&instr->src[num], &reg, sizeof(reg));
527 }
528
529 static const struct allowed_reg_type vs_3_reg_allowed[] = {
530     { BWRITERSPR_TEMP,         32,  FALSE },
531     { BWRITERSPR_INPUT,        16,   TRUE },
532     { BWRITERSPR_CONST,       ~0U,   TRUE },
533     { BWRITERSPR_ADDR,          1,  FALSE },
534     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
535     { BWRITERSPR_CONSTINT,     16,  FALSE },
536     { BWRITERSPR_LOOP,          1,  FALSE },
537     { BWRITERSPR_LABEL,      2048,  FALSE },
538     { BWRITERSPR_PREDICATE,     1,  FALSE },
539     { BWRITERSPR_SAMPLER,       4,  FALSE },
540     { BWRITERSPR_OUTPUT,       12,   TRUE },
541     { ~0U, 0 } /* End tag */
542 };
543
544 static void asmparser_srcreg_vs_3(struct asm_parser *This,
545                                   struct instruction *instr, int num,
546                                   const struct shader_reg *src) {
547     if(!check_reg_type(src, vs_3_reg_allowed)) {
548         asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n",
549                           This->line_no,
550                           debug_print_srcreg(src, ST_VERTEX));
551         set_parse_status(This, PARSE_ERR);
552     }
553     check_loop_swizzle(This, src);
554     check_legacy_srcmod(This, src->srcmod);
555     memcpy(&instr->src[num], src, sizeof(*src));
556 }
557
558 static const struct allowed_reg_type ps_2_0_reg_allowed[] = {
559     { BWRITERSPR_INPUT,         2,  FALSE },
560     { BWRITERSPR_TEMP,         32,  FALSE },
561     { BWRITERSPR_CONST,        32,  FALSE },
562     { BWRITERSPR_CONSTINT,     16,  FALSE },
563     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
564     { BWRITERSPR_SAMPLER,      16,  FALSE },
565     { BWRITERSPR_TEXTURE,       8,  FALSE },
566     { BWRITERSPR_COLOROUT,      4,  FALSE },
567     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
568     { ~0U, 0 } /* End tag */
569 };
570
571 static void asmparser_srcreg_ps_2(struct asm_parser *This,
572                                   struct instruction *instr, int num,
573                                   const struct shader_reg *src) {
574     struct shader_reg reg;
575
576     if(!check_reg_type(src, ps_2_0_reg_allowed)) {
577         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n",
578                           This->line_no,
579                           debug_print_srcreg(src, ST_PIXEL));
580         set_parse_status(This, PARSE_ERR);
581     }
582     check_legacy_srcmod(This, src->srcmod);
583     check_abs_srcmod(This, src->srcmod);
584     reg = map_oldps_register(src, TRUE);
585     memcpy(&instr->src[num], &reg, sizeof(reg));
586 }
587
588 static const struct allowed_reg_type ps_2_x_reg_allowed[] = {
589     { BWRITERSPR_INPUT,         2,  FALSE },
590     { BWRITERSPR_TEMP,         32,  FALSE },
591     { BWRITERSPR_CONST,        32,  FALSE },
592     { BWRITERSPR_CONSTINT,     16,  FALSE },
593     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
594     { BWRITERSPR_PREDICATE,     1,  FALSE },
595     { BWRITERSPR_SAMPLER,      16,  FALSE },
596     { BWRITERSPR_TEXTURE,       8,  FALSE },
597     { BWRITERSPR_LABEL,      2048,  FALSE },
598     { BWRITERSPR_COLOROUT,      4,  FALSE },
599     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
600     { ~0U, 0 } /* End tag */
601 };
602
603 static void asmparser_srcreg_ps_2_x(struct asm_parser *This,
604                                     struct instruction *instr, int num,
605                                     const struct shader_reg *src) {
606     struct shader_reg reg;
607
608     if(!check_reg_type(src, ps_2_x_reg_allowed)) {
609         asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n",
610                           This->line_no,
611                           debug_print_srcreg(src, ST_PIXEL));
612         set_parse_status(This, PARSE_ERR);
613     }
614     check_legacy_srcmod(This, src->srcmod);
615     check_abs_srcmod(This, src->srcmod);
616     reg = map_oldps_register(src, TRUE);
617     memcpy(&instr->src[num], &reg, sizeof(reg));
618 }
619
620 static const struct allowed_reg_type ps_3_reg_allowed[] = {
621     { BWRITERSPR_INPUT,        10,   TRUE },
622     { BWRITERSPR_TEMP,         32,  FALSE },
623     { BWRITERSPR_CONST,       224,  FALSE },
624     { BWRITERSPR_CONSTINT,     16,  FALSE },
625     { BWRITERSPR_CONSTBOOL,    16,  FALSE },
626     { BWRITERSPR_PREDICATE,     1,  FALSE },
627     { BWRITERSPR_SAMPLER,      16,  FALSE },
628     { BWRITERSPR_MISCTYPE,      2,  FALSE }, /* vPos and vFace */
629     { BWRITERSPR_LOOP,          1,  FALSE },
630     { BWRITERSPR_LABEL,      2048,  FALSE },
631     { BWRITERSPR_COLOROUT,      4,  FALSE },
632     { BWRITERSPR_DEPTHOUT,      1,  FALSE },
633     { ~0U, 0 } /* End tag */
634 };
635
636 static void asmparser_srcreg_ps_3(struct asm_parser *This,
637                                   struct instruction *instr, int num,
638                                   const struct shader_reg *src) {
639     if(!check_reg_type(src, ps_3_reg_allowed)) {
640         asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n",
641                           This->line_no,
642                           debug_print_srcreg(src, ST_PIXEL));
643         set_parse_status(This, PARSE_ERR);
644     }
645     check_loop_swizzle(This, src);
646     check_legacy_srcmod(This, src->srcmod);
647     memcpy(&instr->src[num], src, sizeof(*src));
648 }
649
650 static void asmparser_dstreg_vs_1(struct asm_parser *This,
651                                   struct instruction *instr,
652                                   const struct shader_reg *dst) {
653     struct shader_reg reg;
654
655     if(!check_reg_type(dst, vs_1_reg_allowed)) {
656         asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n",
657                           This->line_no,
658                           debug_print_dstreg(dst, ST_VERTEX));
659         set_parse_status(This, PARSE_ERR);
660     }
661     check_ps_dstmod(This, instr->dstmod);
662     check_shift_dstmod(This, instr->shift);
663     reg = map_oldvs_register(dst);
664     memcpy(&instr->dst, &reg, sizeof(reg));
665     instr->has_dst = TRUE;
666 }
667
668 static void asmparser_dstreg_vs_2(struct asm_parser *This,
669                                   struct instruction *instr,
670                                   const struct shader_reg *dst) {
671     struct shader_reg reg;
672
673     if(!check_reg_type(dst, vs_2_reg_allowed)) {
674         asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n",
675                           This->line_no,
676                           debug_print_dstreg(dst, ST_VERTEX));
677         set_parse_status(This, PARSE_ERR);
678     }
679     check_ps_dstmod(This, instr->dstmod);
680     check_shift_dstmod(This, instr->shift);
681     reg = map_oldvs_register(dst);
682     memcpy(&instr->dst, &reg, sizeof(reg));
683     instr->has_dst = TRUE;
684 }
685
686 static void asmparser_dstreg_vs_3(struct asm_parser *This,
687                                   struct instruction *instr,
688                                   const struct shader_reg *dst) {
689     if(!check_reg_type(dst, vs_3_reg_allowed)) {
690         asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n",
691                           This->line_no,
692                           debug_print_dstreg(dst, ST_VERTEX));
693         set_parse_status(This, PARSE_ERR);
694     }
695     check_ps_dstmod(This, instr->dstmod);
696     check_shift_dstmod(This, instr->shift);
697     memcpy(&instr->dst, dst, sizeof(*dst));
698     instr->has_dst = TRUE;
699 }
700
701 static void asmparser_dstreg_ps_2(struct asm_parser *This,
702                                   struct instruction *instr,
703                                   const struct shader_reg *dst) {
704     struct shader_reg reg;
705
706     if(!check_reg_type(dst, ps_2_0_reg_allowed)) {
707         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n",
708                           This->line_no,
709                           debug_print_dstreg(dst, ST_PIXEL));
710         set_parse_status(This, PARSE_ERR);
711     }
712     check_shift_dstmod(This, instr->shift);
713     reg = map_oldps_register(dst, TRUE);
714     memcpy(&instr->dst, &reg, sizeof(reg));
715     instr->has_dst = TRUE;
716 }
717
718 static void asmparser_dstreg_ps_2_x(struct asm_parser *This,
719                                     struct instruction *instr,
720                                     const struct shader_reg *dst) {
721     struct shader_reg reg;
722
723     if(!check_reg_type(dst, ps_2_x_reg_allowed)) {
724         asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n",
725                           This->line_no,
726                           debug_print_dstreg(dst, ST_PIXEL));
727         set_parse_status(This, PARSE_ERR);
728     }
729     check_shift_dstmod(This, instr->shift);
730     reg = map_oldps_register(dst, TRUE);
731     memcpy(&instr->dst, &reg, sizeof(reg));
732     instr->has_dst = TRUE;
733 }
734
735 static void asmparser_dstreg_ps_3(struct asm_parser *This,
736                                   struct instruction *instr,
737                                   const struct shader_reg *dst) {
738     if(!check_reg_type(dst, ps_3_reg_allowed)) {
739         asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n",
740                           This->line_no,
741                           debug_print_dstreg(dst, ST_PIXEL));
742         set_parse_status(This, PARSE_ERR);
743     }
744     check_shift_dstmod(This, instr->shift);
745     memcpy(&instr->dst, dst, sizeof(*dst));
746     instr->has_dst = TRUE;
747 }
748
749 static void asmparser_predicate_supported(struct asm_parser *This,
750                                           const struct shader_reg *predicate) {
751     /* this sets the predicate of the last instruction added to the shader */
752     if(!This->shader) return;
753     if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n");
754     This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE;
755     memcpy(&This->shader->instr[This->shader->num_instrs - 1]->predicate, predicate, sizeof(*predicate));
756 }
757
758 static void asmparser_predicate_unsupported(struct asm_parser *This,
759                                             const struct shader_reg *predicate) {
760     asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
761     set_parse_status(This, PARSE_ERR);
762 }
763
764 static void asmparser_coissue_unsupported(struct asm_parser *This) {
765     asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
766     set_parse_status(This, PARSE_ERR);
767 }
768
769 static const struct asmparser_backend parser_vs_1 = {
770     asmparser_constF,
771     asmparser_constI,
772     asmparser_constB,
773
774     asmparser_dstreg_vs_1,
775     asmparser_srcreg_vs_1,
776
777     asmparser_predicate_unsupported,
778     asmparser_coissue_unsupported,
779
780     asmparser_dcl_output,
781     asmparser_dcl_input,
782     asmparser_dcl_sampler,
783
784     asmparser_end,
785
786     asmparser_instr,
787 };
788
789 static const struct asmparser_backend parser_vs_2 = {
790     asmparser_constF,
791     asmparser_constI,
792     asmparser_constB,
793
794     asmparser_dstreg_vs_2,
795     asmparser_srcreg_vs_2,
796
797     asmparser_predicate_supported,
798     asmparser_coissue_unsupported,
799
800     asmparser_dcl_output,
801     asmparser_dcl_input,
802     asmparser_dcl_sampler,
803
804     asmparser_end,
805
806     asmparser_instr,
807 };
808
809 static const struct asmparser_backend parser_vs_3 = {
810     asmparser_constF,
811     asmparser_constI,
812     asmparser_constB,
813
814     asmparser_dstreg_vs_3,
815     asmparser_srcreg_vs_3,
816
817     asmparser_predicate_supported,
818     asmparser_coissue_unsupported,
819
820     asmparser_dcl_output,
821     asmparser_dcl_input,
822     asmparser_dcl_sampler,
823
824     asmparser_end,
825
826     asmparser_instr,
827 };
828
829 static const struct asmparser_backend parser_ps_2 = {
830     asmparser_constF,
831     asmparser_constI,
832     asmparser_constB,
833
834     asmparser_dstreg_ps_2,
835     asmparser_srcreg_ps_2,
836
837     asmparser_predicate_unsupported,
838     asmparser_coissue_unsupported,
839
840     asmparser_dcl_output,
841     asmparser_dcl_input_ps_2,
842     asmparser_dcl_sampler,
843
844     asmparser_end,
845
846     asmparser_instr,
847 };
848
849 static const struct asmparser_backend parser_ps_2_x = {
850     asmparser_constF,
851     asmparser_constI,
852     asmparser_constB,
853
854     asmparser_dstreg_ps_2_x,
855     asmparser_srcreg_ps_2_x,
856
857     asmparser_predicate_supported,
858     asmparser_coissue_unsupported,
859
860     asmparser_dcl_output,
861     asmparser_dcl_input_ps_2,
862     asmparser_dcl_sampler,
863
864     asmparser_end,
865
866     asmparser_instr,
867 };
868
869 static const struct asmparser_backend parser_ps_3 = {
870     asmparser_constF,
871     asmparser_constI,
872     asmparser_constB,
873
874     asmparser_dstreg_ps_3,
875     asmparser_srcreg_ps_3,
876
877     asmparser_predicate_supported,
878     asmparser_coissue_unsupported,
879
880     asmparser_dcl_output,
881     asmparser_dcl_input,
882     asmparser_dcl_sampler,
883
884     asmparser_end,
885
886     asmparser_instr,
887 };
888
889 static void gen_oldvs_output(struct bwriter_shader *shader) {
890     record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
891     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
892     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
893     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
894     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
895     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
896     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
897     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
898     record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
899     record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, 0, TRUE, OFOG_REG, OFOG_WRITEMASK, TRUE);
900     record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, 0, TRUE, OPTS_REG, OPTS_WRITEMASK, TRUE);
901     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
902     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL, TRUE);
903 }
904
905 static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
906     switch(texcoords) {
907         case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
908         case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
909         case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
910         case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
911         case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
912         case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
913         case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
914         case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
915     };
916     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
917     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE);
918 }
919
920 void create_vs10_parser(struct asm_parser *ret) {
921     TRACE_(parsed_shader)("vs_1_0\n");
922
923     ret->shader = asm_alloc(sizeof(*ret->shader));
924     if(!ret->shader) {
925         ERR("Failed to allocate memory for the shader\n");
926         set_parse_status(ret, PARSE_ERR);
927         return;
928     }
929
930     ret->shader->type = ST_VERTEX;
931     ret->shader->version = BWRITERVS_VERSION(1, 0);
932     ret->funcs = &parser_vs_1;
933     gen_oldvs_output(ret->shader);
934 }
935
936 void create_vs11_parser(struct asm_parser *ret) {
937     TRACE_(parsed_shader)("vs_1_1\n");
938
939     ret->shader = asm_alloc(sizeof(*ret->shader));
940     if(!ret->shader) {
941         ERR("Failed to allocate memory for the shader\n");
942         set_parse_status(ret, PARSE_ERR);
943         return;
944     }
945
946     ret->shader->type = ST_VERTEX;
947     ret->shader->version = BWRITERVS_VERSION(1, 1);
948     ret->funcs = &parser_vs_1;
949     gen_oldvs_output(ret->shader);
950 }
951
952 void create_vs20_parser(struct asm_parser *ret) {
953     TRACE_(parsed_shader)("vs_2_0\n");
954
955     ret->shader = asm_alloc(sizeof(*ret->shader));
956     if(!ret->shader) {
957         ERR("Failed to allocate memory for the shader\n");
958         set_parse_status(ret, PARSE_ERR);
959         return;
960     }
961
962     ret->shader->type = ST_VERTEX;
963     ret->shader->version = BWRITERVS_VERSION(2, 0);
964     ret->funcs = &parser_vs_2;
965     gen_oldvs_output(ret->shader);
966 }
967
968 void create_vs2x_parser(struct asm_parser *ret) {
969     TRACE_(parsed_shader)("vs_2_x\n");
970
971     ret->shader = asm_alloc(sizeof(*ret->shader));
972     if(!ret->shader) {
973         ERR("Failed to allocate memory for the shader\n");
974         set_parse_status(ret, PARSE_ERR);
975         return;
976     }
977
978     ret->shader->type = ST_VERTEX;
979     ret->shader->version = BWRITERVS_VERSION(2, 1);
980     ret->funcs = &parser_vs_2;
981     gen_oldvs_output(ret->shader);
982 }
983
984 void create_vs30_parser(struct asm_parser *ret) {
985     TRACE_(parsed_shader)("vs_3_0\n");
986
987     ret->shader = asm_alloc(sizeof(*ret->shader));
988     if(!ret->shader) {
989         ERR("Failed to allocate memory for the shader\n");
990         set_parse_status(ret, PARSE_ERR);
991         return;
992     }
993
994     ret->shader->type = ST_VERTEX;
995     ret->shader->version = BWRITERVS_VERSION(3, 0);
996     ret->funcs = &parser_vs_3;
997 }
998
999 void create_ps20_parser(struct asm_parser *ret) {
1000     TRACE_(parsed_shader)("ps_2_0\n");
1001
1002     ret->shader = asm_alloc(sizeof(*ret->shader));
1003     if(!ret->shader) {
1004         ERR("Failed to allocate memory for the shader\n");
1005         set_parse_status(ret, PARSE_ERR);
1006         return;
1007     }
1008
1009     ret->shader->type = ST_PIXEL;
1010     ret->shader->version = BWRITERPS_VERSION(2, 0);
1011     ret->funcs = &parser_ps_2;
1012     gen_oldps_input(ret->shader, 8);
1013 }
1014
1015 void create_ps2x_parser(struct asm_parser *ret) {
1016     TRACE_(parsed_shader)("ps_2_x\n");
1017
1018     ret->shader = asm_alloc(sizeof(*ret->shader));
1019     if(!ret->shader) {
1020         ERR("Failed to allocate memory for the shader\n");
1021         set_parse_status(ret, PARSE_ERR);
1022         return;
1023     }
1024
1025     ret->shader->type = ST_PIXEL;
1026     ret->shader->version = BWRITERPS_VERSION(2, 1);
1027     ret->funcs = &parser_ps_2_x;
1028     gen_oldps_input(ret->shader, 8);
1029 }
1030
1031 void create_ps30_parser(struct asm_parser *ret) {
1032     TRACE_(parsed_shader)("ps_3_0\n");
1033
1034     ret->shader = asm_alloc(sizeof(*ret->shader));
1035     if(!ret->shader) {
1036         ERR("Failed to allocate memory for the shader\n");
1037         set_parse_status(ret, PARSE_ERR);
1038         return;
1039     }
1040
1041     ret->shader->type = ST_PIXEL;
1042     ret->shader->version = BWRITERPS_VERSION(3, 0);
1043     ret->funcs = &parser_ps_3;
1044 }