d3dx9: Add DEF instruction support in the shader assembler.
[wine] / dlls / d3dx9_36 / bytecodewriter.c
1 /*
2  * Direct3D bytecode output functions
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
31 /****************************************************************
32  * General assembler shader construction helper routines follow *
33  ****************************************************************/
34 /* struct instruction *alloc_instr
35  *
36  * Allocates a new instruction structure with srcs registers
37  *
38  * Parameters:
39  *  srcs: Number of source registers to allocate
40  *
41  * Returns:
42  *  A pointer to the allocated instruction structure
43  *  NULL in case of an allocation failure
44  */
45 struct instruction *alloc_instr(unsigned int srcs) {
46     struct instruction *ret = asm_alloc(sizeof(*ret));
47     if(!ret) {
48         ERR("Failed to allocate memory for an instruction structure\n");
49         return NULL;
50     }
51
52     if(srcs) {
53         ret->src = asm_alloc(srcs * sizeof(*ret->src));
54         if(!ret->src) {
55             ERR("Failed to allocate memory for instruction registers\n");
56             asm_free(ret);
57             return NULL;
58         }
59         ret->num_srcs = srcs;
60     }
61     return ret;
62 }
63
64 /* void add_instruction
65  *
66  * Adds a new instruction to the shader's instructions array and grows the instruction array
67  * if needed.
68  *
69  * The function does NOT copy the instruction structure. Make sure not to release the
70  * instruction or any of its substructures like registers.
71  *
72  * Parameters:
73  *  shader: Shader to add the instruction to
74  *  instr: Instruction to add to the shader
75  */
76 BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr) {
77     struct instruction      **new_instructions;
78
79     if(!shader) return FALSE;
80
81     if(shader->instr_alloc_size == 0) {
82         shader->instr = asm_alloc(sizeof(*shader->instr) * INSTRARRAY_INITIAL_SIZE);
83         if(!shader->instr) {
84             ERR("Failed to allocate the shader instruction array\n");
85             return FALSE;
86         }
87         shader->instr_alloc_size = INSTRARRAY_INITIAL_SIZE;
88     } else if(shader->instr_alloc_size == shader->num_instrs) {
89         new_instructions = asm_realloc(shader->instr,
90                                        sizeof(*shader->instr) * (shader->instr_alloc_size) * 2);
91         if(!new_instructions) {
92             ERR("Failed to grow the shader instruction array\n");
93             return FALSE;
94         }
95         shader->instr = new_instructions;
96         shader->instr_alloc_size = shader->instr_alloc_size * 2;
97     } else if(shader->num_instrs > shader->instr_alloc_size) {
98         ERR("More instructions than allocated. This should not happen\n");
99         return FALSE;
100     }
101
102     shader->instr[shader->num_instrs] = instr;
103     shader->num_instrs++;
104     return TRUE;
105 }
106
107 BOOL add_constF(struct bwriter_shader *shader, DWORD reg, float x, float y, float z, float w) {
108     struct constant *newconst;
109
110     if(shader->num_cf) {
111         struct constant **newarray;
112         newarray = asm_realloc(shader->constF,
113                                sizeof(*shader->constF) * (shader->num_cf + 1));
114         if(!newarray) {
115             ERR("Failed to grow the constants array\n");
116             return FALSE;
117         }
118         shader->constF = newarray;
119     } else {
120         shader->constF = asm_alloc(sizeof(*shader->constF));
121         if(!shader->constF) {
122             ERR("Failed to allocate the constants array\n");
123             return FALSE;
124         }
125     }
126
127     newconst = asm_alloc(sizeof(*newconst));
128     if(!newconst) {
129         ERR("Failed to allocate a new constant\n");
130         return FALSE;
131     }
132     newconst->regnum = reg;
133     newconst->value[0].f = x;
134     newconst->value[1].f = y;
135     newconst->value[2].f = z;
136     newconst->value[3].f = w;
137     shader->constF[shader->num_cf] = newconst;
138
139     shader->num_cf++;
140     return TRUE;
141 }
142
143 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) {
144     unsigned int *num;
145     struct declaration **decl;
146     unsigned int i;
147
148     if(!shader) return FALSE;
149
150     if(output) {
151         num = &shader->num_outputs;
152         decl = &shader->outputs;
153     } else {
154         num = &shader->num_inputs;
155         decl = &shader->inputs;
156     }
157
158     if(*num == 0) {
159         *decl = asm_alloc(sizeof(**decl));
160         if(!*decl) {
161             ERR("Error allocating declarations array\n");
162             return FALSE;
163         }
164     } else {
165         struct declaration *newdecl;
166         for(i = 0; i < *num; i++) {
167             if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
168                 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
169                       regnum, (*decl)[i].writemask & writemask);
170             }
171         }
172
173         newdecl = asm_realloc(*decl,
174                               sizeof(**decl) * ((*num) + 1));
175         if(!newdecl) {
176             ERR("Error reallocating declarations array\n");
177             return FALSE;
178         }
179         *decl = newdecl;
180     }
181     (*decl)[*num].usage = usage;
182     (*decl)[*num].usage_idx = usage_idx;
183     (*decl)[*num].regnum = regnum;
184     (*decl)[*num].writemask = writemask;
185     (*num)++;
186
187     return TRUE;
188 }
189
190 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD regnum) {
191     unsigned int i;
192
193     if(!shader) return FALSE;
194
195     if(shader->num_samplers == 0) {
196         shader->samplers = asm_alloc(sizeof(*shader->samplers));
197         if(!shader->samplers) {
198             ERR("Error allocating samplers array\n");
199             return FALSE;
200         }
201     } else {
202         struct samplerdecl *newarray;
203
204         for(i = 0; i < shader->num_samplers; i++) {
205             if(shader->samplers[i].regnum == regnum) {
206                 WARN("Sampler %u already declared\n", regnum);
207                 /* This is not an error as far as the assembler is concerned.
208                  * Direct3D might refuse to load the compiled shader though
209                  */
210             }
211         }
212
213         newarray = asm_realloc(shader->samplers,
214                                sizeof(*shader->samplers) * (shader->num_samplers + 1));
215         if(!newarray) {
216             ERR("Error reallocating samplers array\n");
217             return FALSE;
218         }
219         shader->samplers = newarray;
220     }
221
222     shader->samplers[shader->num_samplers].type = samptype;
223     shader->samplers[shader->num_samplers].regnum = regnum;
224     shader->num_samplers++;
225     return TRUE;
226 }
227
228
229 /* shader bytecode buffer manipulation functions.
230  * allocate_buffer creates a new buffer structure, put_dword adds a new
231  * DWORD to the buffer. In the rare case of a memory allocation failure
232  * when trying to grow the buffer a flag is set in the buffer to mark it
233  * invalid. This avoids return value checking and passing in many places
234  */
235 static struct bytecode_buffer *allocate_buffer(void) {
236     struct bytecode_buffer *ret;
237
238     ret = asm_alloc(sizeof(*ret));
239     if(!ret) return NULL;
240
241     ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
242     ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
243     if(!ret->data) {
244         asm_free(ret);
245         return NULL;
246     }
247     ret->state = S_OK;
248     return ret;
249 }
250
251 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
252     if(FAILED(buffer->state)) return;
253
254     if(buffer->alloc_size == buffer->size) {
255         DWORD *newarray;
256         buffer->alloc_size *= 2;
257         newarray = asm_realloc(buffer->data,
258                                sizeof(DWORD) * buffer->alloc_size);
259         if(!newarray) {
260             ERR("Failed to grow the buffer data memory\n");
261             buffer->state = E_OUTOFMEMORY;
262             return;
263         }
264         buffer->data = newarray;
265     }
266     buffer->data[buffer->size++] = value;
267 }
268
269 /******************************************************
270  * Implementation of the writer functions starts here *
271  ******************************************************/
272 static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
273                                const struct declaration *decls, unsigned int num, DWORD type) {
274     DWORD i;
275     DWORD instr_dcl = D3DSIO_DCL;
276     DWORD token;
277
278     if(len) {
279         instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
280     }
281
282     for(i = 0; i < num; i++) {
283         /* Write the DCL instruction */
284         put_dword(buffer, instr_dcl);
285
286         /* Write the usage and index */
287         token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
288         token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
289         token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
290         put_dword(buffer, token);
291
292         /* Write the dest register */
293         token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
294         token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
295         token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL;
296         token |= decls[i].regnum & D3DSP_REGNUM_MASK;
297         put_dword(buffer, token);
298     }
299 }
300
301 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
302     DWORD i;
303     DWORD instr_def = D3DSIO_DEF;
304     const DWORD reg = (1<<31) |
305                       ((D3DSPR_CONST << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
306                       D3DSP_WRITEMASK_ALL;
307
308     if(len) {
309         instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
310     }
311
312     for(i = 0; i < shader->num_cf; i++) {
313         /* Write the DEF instruction */
314         put_dword(buffer, instr_def);
315
316         put_dword(buffer, reg | (shader->constF[i]->regnum & D3DSP_REGNUM_MASK));
317         put_dword(buffer, shader->constF[i]->value[0].d);
318         put_dword(buffer, shader->constF[i]->value[1].d);
319         put_dword(buffer, shader->constF[i]->value[2].d);
320         put_dword(buffer, shader->constF[i]->value[3].d);
321     }
322 }
323
324 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
325     put_dword(buffer, D3DSIO_END);
326 }
327
328 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
329                           struct bytecode_buffer *buffer){
330     unsigned int i;
331     if(instr->has_predicate){
332         This->funcs->srcreg(This, &instr->predicate, buffer);
333     }
334     for(i = 0; i < instr->num_srcs; i++){
335         This->funcs->srcreg(This, &instr->src[i], buffer);
336     }
337 }
338
339 /* The length of an instruction consists of the destination register (if any),
340  * the number of source registers, the number of address registers used for
341  * indirect addressing, and optionally the predicate register
342  */
343 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
344     unsigned int i;
345     DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
346
347     if(dsts){
348         if(instr->dst.rel_reg) ret++;
349     }
350     for(i = 0; i < srcs; i++) {
351         if(instr->src[i].rel_reg) ret++;
352     }
353     return ret;
354 }
355
356 static void instr_handler(struct bc_writer *This,
357                           const struct instruction *instr,
358                           struct bytecode_buffer *buffer) {
359     DWORD token = d3d9_opcode(instr->opcode);
360     TRACE("token: %x\n", token);
361
362     This->funcs->opcode(This, instr, token, buffer);
363     if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
364     write_srcregs(This, instr, buffer);
365 }
366
367 static void sm_2_opcode(struct bc_writer *This,
368                         const struct instruction *instr,
369                         DWORD token, struct bytecode_buffer *buffer) {
370     /* From sm 2 onwards instruction length is encoded in the opcode field */
371     int dsts = instr->has_dst ? 1 : 0;
372     token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
373     if(instr->comptype)
374         token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
375     if(instr->has_predicate)
376         token |= D3DSHADER_INSTRUCTION_PREDICATED;
377     put_dword(buffer,token);
378 }
379
380 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
381     DWORD i;
382     DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
383     DWORD token;
384     const DWORD reg = (1<<31) |
385                       ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
386                       ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
387                       D3DSP_WRITEMASK_ALL;
388
389     for(i = 0; i < shader->num_samplers; i++) {
390         /* Write the DCL instruction */
391         put_dword(buffer, instr_dcl);
392         token = (1<<31);
393         /* Already shifted */
394         token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
395         put_dword(buffer, token);
396         put_dword(buffer, reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK));
397     }
398 }
399
400 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
401     /* Declare the shader type and version */
402     put_dword(buffer, This->version);
403
404     write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
405     write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT);
406     write_constF(shader, buffer, TRUE);
407     write_samplers(shader, buffer);
408     return;
409 }
410
411 static void sm_3_srcreg(struct bc_writer *This,
412                         const struct shader_reg *reg,
413                         struct bytecode_buffer *buffer) {
414     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
415     DWORD d3d9reg;
416
417     d3d9reg = d3d9_register(reg->type);
418     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
419     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
420     token |= reg->regnum & D3DSP_REGNUM_MASK;
421
422     token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
423     token |= d3d9_srcmod(reg->srcmod);
424
425     if(reg->rel_reg) {
426         if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
427             WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
428             This->state = E_INVALIDARG;
429             return;
430         }
431         if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
432            reg->rel_reg->type == BWRITERSPR_LOOP) &&
433            reg->rel_reg->regnum == 0) {
434             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
435         } else {
436             WARN("Unsupported relative addressing register\n");
437             This->state = E_INVALIDARG;
438             return;
439         }
440     }
441
442     put_dword(buffer, token);
443
444     /* vs_2_0 and newer write the register containing the index explicitly in the
445      * binary code
446      */
447     if(token & D3DVS_ADDRMODE_RELATIVE) {
448         sm_3_srcreg(This, reg->rel_reg, buffer);
449     }
450 }
451
452 static void sm_3_dstreg(struct bc_writer *This,
453                         const struct shader_reg *reg,
454                         struct bytecode_buffer *buffer,
455                         DWORD shift, DWORD mod) {
456     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
457     DWORD d3d9reg;
458
459     if(reg->rel_reg) {
460         if(This->version == BWRITERVS_VERSION(3, 0) &&
461            reg->type == BWRITERSPR_OUTPUT) {
462             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
463         } else {
464             WARN("Relative addressing not supported for this shader type or register type\n");
465             This->state = E_INVALIDARG;
466             return;
467         }
468     }
469
470     d3d9reg = d3d9_register(reg->type);
471     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
472     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
473     token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
474
475     token |= d3d9_dstmod(mod);
476
477     token |= d3d9_writemask(reg->writemask);
478     put_dword(buffer, token);
479
480     /* vs_2_0 and newer write the register containing the index explicitly in the
481      * binary code
482      */
483     if(token & D3DVS_ADDRMODE_RELATIVE) {
484         sm_3_srcreg(This, reg->rel_reg, buffer);
485     }
486 }
487
488 static const struct instr_handler_table vs_3_handlers[] = {
489     {BWRITERSIO_ADD,            instr_handler},
490     {BWRITERSIO_NOP,            instr_handler},
491     {BWRITERSIO_MOV,            instr_handler},
492     {BWRITERSIO_SUB,            instr_handler},
493     {BWRITERSIO_MAD,            instr_handler},
494     {BWRITERSIO_MUL,            instr_handler},
495     {BWRITERSIO_RCP,            instr_handler},
496     {BWRITERSIO_RSQ,            instr_handler},
497     {BWRITERSIO_DP3,            instr_handler},
498     {BWRITERSIO_DP4,            instr_handler},
499     {BWRITERSIO_MIN,            instr_handler},
500     {BWRITERSIO_MAX,            instr_handler},
501     {BWRITERSIO_SLT,            instr_handler},
502     {BWRITERSIO_SGE,            instr_handler},
503     {BWRITERSIO_ABS,            instr_handler},
504     {BWRITERSIO_EXP,            instr_handler},
505     {BWRITERSIO_LOG,            instr_handler},
506     {BWRITERSIO_EXPP,           instr_handler},
507     {BWRITERSIO_LOGP,           instr_handler},
508     {BWRITERSIO_DST,            instr_handler},
509     {BWRITERSIO_LRP,            instr_handler},
510     {BWRITERSIO_FRC,            instr_handler},
511     {BWRITERSIO_CRS,            instr_handler},
512     {BWRITERSIO_SGN,            instr_handler},
513     {BWRITERSIO_NRM,            instr_handler},
514     {BWRITERSIO_SINCOS,         instr_handler},
515     {BWRITERSIO_M4x4,           instr_handler},
516     {BWRITERSIO_M4x3,           instr_handler},
517     {BWRITERSIO_M3x4,           instr_handler},
518     {BWRITERSIO_M3x3,           instr_handler},
519     {BWRITERSIO_M3x2,           instr_handler},
520     {BWRITERSIO_LIT,            instr_handler},
521     {BWRITERSIO_POW,            instr_handler},
522     {BWRITERSIO_MOVA,           instr_handler},
523
524     {BWRITERSIO_CALL,           instr_handler},
525     {BWRITERSIO_CALLNZ,         instr_handler},
526     {BWRITERSIO_REP,            instr_handler},
527     {BWRITERSIO_ENDREP,         instr_handler},
528     {BWRITERSIO_IF,             instr_handler},
529     {BWRITERSIO_LABEL,          instr_handler},
530     {BWRITERSIO_IFC,            instr_handler},
531     {BWRITERSIO_ELSE,           instr_handler},
532     {BWRITERSIO_ENDIF,          instr_handler},
533     {BWRITERSIO_BREAK,          instr_handler},
534     {BWRITERSIO_BREAKC,         instr_handler},
535     {BWRITERSIO_LOOP,           instr_handler},
536     {BWRITERSIO_RET,            instr_handler},
537     {BWRITERSIO_ENDLOOP,        instr_handler},
538
539     {BWRITERSIO_SETP,           instr_handler},
540     {BWRITERSIO_BREAKP,         instr_handler},
541     {BWRITERSIO_TEXLDL,         instr_handler},
542
543     {BWRITERSIO_END,            NULL},
544 };
545
546 static const struct bytecode_backend vs_3_backend = {
547     sm_3_header,
548     end,
549     sm_3_srcreg,
550     sm_3_dstreg,
551     sm_2_opcode,
552     vs_3_handlers
553 };
554
555 static void init_vs30_dx9_writer(struct bc_writer *writer) {
556     TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
557     writer->funcs = &vs_3_backend;
558 }
559
560 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
561     struct bc_writer *ret = asm_alloc(sizeof(*ret));
562
563     if(!ret) {
564         WARN("Failed to allocate a bytecode writer instance\n");
565         return NULL;
566     }
567
568     switch(version) {
569         case BWRITERVS_VERSION(1, 0):
570             if(dxversion != 9) {
571                 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
572                 goto fail;
573             }
574             /* TODO: Set the appropriate writer backend */
575             break;
576         case BWRITERVS_VERSION(1, 1):
577             if(dxversion != 9) {
578                 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
579                 goto fail;
580             }
581             /* TODO: Set the appropriate writer backend */
582             break;
583         case BWRITERVS_VERSION(2, 0):
584             if(dxversion != 9) {
585                 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
586                 goto fail;
587             }
588             /* TODO: Set the appropriate writer backend */
589             break;
590         case BWRITERVS_VERSION(2, 1):
591             if(dxversion != 9) {
592                 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
593                 goto fail;
594             }
595             /* TODO: Set the appropriate writer backend */
596             break;
597         case BWRITERVS_VERSION(3, 0):
598             if(dxversion != 9) {
599                 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
600                 goto fail;
601             }
602             init_vs30_dx9_writer(ret);
603             break;
604
605         case BWRITERPS_VERSION(1, 0):
606             if(dxversion != 9) {
607                 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
608                 goto fail;
609             }
610             /* TODO: Set the appropriate writer backend */
611             break;
612         case BWRITERPS_VERSION(1, 1):
613             if(dxversion != 9) {
614                 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
615                 goto fail;
616             }
617             /* TODO: Set the appropriate writer backend */
618             break;
619         case BWRITERPS_VERSION(1, 2):
620             if(dxversion != 9) {
621                 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
622                 goto fail;
623             }
624             /* TODO: Set the appropriate writer backend */
625             break;
626         case BWRITERPS_VERSION(1, 3):
627             if(dxversion != 9) {
628                 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
629                 goto fail;
630             }
631             /* TODO: Set the appropriate writer backend */
632             break;
633         case BWRITERPS_VERSION(1, 4):
634             if(dxversion != 9) {
635                 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
636                 goto fail;
637             }
638             /* TODO: Set the appropriate writer backend */
639             break;
640
641         case BWRITERPS_VERSION(2, 0):
642             if(dxversion != 9) {
643                 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
644                 goto fail;
645             }
646             /* TODO: Set the appropriate writer backend */
647             break;
648
649         case BWRITERPS_VERSION(2, 1):
650             if(dxversion != 9) {
651                 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
652                 goto fail;
653             }
654             /* TODO: Set the appropriate writer backend */
655             break;
656
657         case BWRITERPS_VERSION(3, 0):
658             if(dxversion != 9) {
659                 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
660                 goto fail;
661             }
662             /* TODO: Set the appropriate writer backend */
663             break;
664
665         default:
666             WARN("Unexpected shader version requested: %08x\n", version);
667             goto fail;
668     }
669     ret->version = version;
670     return ret;
671
672 fail:
673     asm_free(ret);
674     return NULL;
675 }
676
677 static HRESULT call_instr_handler(struct bc_writer *writer,
678                                   const struct instruction *instr,
679                                   struct bytecode_buffer *buffer) {
680     DWORD i=0;
681
682     while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
683         if(instr->opcode == writer->funcs->instructions[i].opcode) {
684             if(!writer->funcs->instructions[i].func) {
685                 WARN("Opcode %u not supported by this profile\n", instr->opcode);
686                 return E_INVALIDARG;
687             }
688             writer->funcs->instructions[i].func(writer, instr, buffer);
689             return S_OK;
690         }
691         i++;
692     }
693
694     FIXME("Unhandled instruction %u\n", instr->opcode);
695     return E_INVALIDARG;
696 }
697
698 /* SlWriteBytecode (wineshader.@)
699  *
700  * Writes shader version specific bytecode from the shader passed in.
701  * The returned bytecode can be passed to the Direct3D runtime like
702  * IDirect3DDevice9::Create*Shader.
703  *
704  * Parameters:
705  *  shader: Shader to translate into bytecode
706  *  version: Shader version to generate(d3d version token)
707  *  dxversion: DirectX version the code targets
708  *  result: the resulting shader bytecode
709  *
710  * Return values:
711  *  S_OK on success
712  */
713 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
714     struct bc_writer *writer;
715     struct bytecode_buffer *buffer = NULL;
716     HRESULT hr;
717     unsigned int i;
718
719     if(!shader){
720         ERR("NULL shader structure, aborting\n");
721         return E_FAIL;
722     }
723     writer = create_writer(shader->version, dxversion);
724     *result = NULL;
725
726     if(!writer) {
727         WARN("Could not create a bytecode writer instance. Either unsupported version\n");
728         WARN("or out of memory\n");
729         hr = E_FAIL;
730         goto error;
731     }
732
733     buffer = allocate_buffer();
734     if(!buffer) {
735         WARN("Failed to allocate a buffer for the shader bytecode\n");
736         hr = E_FAIL;
737         goto error;
738     }
739
740     writer->funcs->header(writer, shader, buffer);
741     if(FAILED(writer->state)) {
742         hr = writer->state;
743         goto error;
744     }
745
746     for(i = 0; i < shader->num_instrs; i++) {
747         hr = call_instr_handler(writer, shader->instr[i], buffer);
748         if(FAILED(hr)) {
749             goto error;
750         }
751     }
752
753     if(FAILED(writer->state)) {
754         hr = writer->state;
755         goto error;
756     }
757
758     writer->funcs->end(writer, shader, buffer);
759
760     if(FAILED(buffer->state)) {
761         hr = buffer->state;
762         goto error;
763     }
764
765     /* Cut off unneeded memory from the result buffer */
766     *result = asm_realloc(buffer->data,
767                          sizeof(DWORD) * buffer->size);
768     if(!*result) {
769         *result = buffer->data;
770     }
771     buffer->data = NULL;
772     hr = S_OK;
773
774 error:
775     if(buffer) {
776         asm_free(buffer->data);
777         asm_free(buffer);
778     }
779     asm_free(writer);
780     return hr;
781 }
782
783 void SlDeleteShader(struct bwriter_shader *shader) {
784     unsigned int i, j;
785
786     TRACE("Deleting shader %p\n", shader);
787
788     for(i = 0; i < shader->num_cf; i++) {
789         asm_free(shader->constF[i]);
790     }
791     asm_free(shader->constF);
792     for(i = 0; i < shader->num_ci; i++) {
793         asm_free(shader->constI[i]);
794     }
795     asm_free(shader->constI);
796     for(i = 0; i < shader->num_cb; i++) {
797         asm_free(shader->constB[i]);
798     }
799     asm_free(shader->constB);
800
801     asm_free(shader->inputs);
802     asm_free(shader->outputs);
803     asm_free(shader->samplers);
804
805     for(i = 0; i < shader->num_instrs; i++) {
806         for(j = 0; j < shader->instr[i]->num_srcs; j++) {
807             asm_free(shader->instr[i]->src[j].rel_reg);
808         }
809         asm_free(shader->instr[i]->src);
810         asm_free(shader->instr[i]);
811     }
812     asm_free(shader->instr);
813
814     asm_free(shader);
815 }