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