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