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