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