d3dx9: Use separate opcodes for TEXLDP and TEXLDB.
[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 add_constI(struct bwriter_shader *shader, DWORD reg, INT x, INT y, INT z, INT w) {
144     struct constant *newconst;
145
146     if(shader->num_ci) {
147         struct constant **newarray;
148         newarray = asm_realloc(shader->constI,
149                                sizeof(*shader->constI) * (shader->num_ci + 1));
150         if(!newarray) {
151             ERR("Failed to grow the constants array\n");
152             return FALSE;
153         }
154         shader->constI = newarray;
155     } else {
156         shader->constI = asm_alloc(sizeof(*shader->constI));
157         if(!shader->constI) {
158             ERR("Failed to allocate the constants array\n");
159             return FALSE;
160         }
161     }
162
163     newconst = asm_alloc(sizeof(*newconst));
164     if(!newconst) {
165         ERR("Failed to allocate a new constant\n");
166         return FALSE;
167     }
168     newconst->regnum = reg;
169     newconst->value[0].i = x;
170     newconst->value[1].i = y;
171     newconst->value[2].i = z;
172     newconst->value[3].i = w;
173     shader->constI[shader->num_ci] = newconst;
174
175     shader->num_ci++;
176     return TRUE;
177 }
178
179 BOOL add_constB(struct bwriter_shader *shader, DWORD reg, BOOL x) {
180     struct constant *newconst;
181
182     if(shader->num_cb) {
183         struct constant **newarray;
184         newarray = asm_realloc(shader->constB,
185                                sizeof(*shader->constB) * (shader->num_cb + 1));
186         if(!newarray) {
187             ERR("Failed to grow the constants array\n");
188             return FALSE;
189         }
190         shader->constB = newarray;
191     } else {
192         shader->constB = asm_alloc(sizeof(*shader->constB));
193         if(!shader->constB) {
194             ERR("Failed to allocate the constants array\n");
195             return FALSE;
196         }
197     }
198
199     newconst = asm_alloc(sizeof(*newconst));
200     if(!newconst) {
201         ERR("Failed to allocate a new constant\n");
202         return FALSE;
203     }
204     newconst->regnum = reg;
205     newconst->value[0].b = x;
206     shader->constB[shader->num_cb] = newconst;
207
208     shader->num_cb++;
209     return TRUE;
210 }
211
212 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) {
213     unsigned int *num;
214     struct declaration **decl;
215     unsigned int i;
216
217     if(!shader) return FALSE;
218
219     if(output) {
220         num = &shader->num_outputs;
221         decl = &shader->outputs;
222     } else {
223         num = &shader->num_inputs;
224         decl = &shader->inputs;
225     }
226
227     if(*num == 0) {
228         *decl = asm_alloc(sizeof(**decl));
229         if(!*decl) {
230             ERR("Error allocating declarations array\n");
231             return FALSE;
232         }
233     } else {
234         struct declaration *newdecl;
235         for(i = 0; i < *num; i++) {
236             if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
237                 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
238                       regnum, (*decl)[i].writemask & writemask);
239             }
240         }
241
242         newdecl = asm_realloc(*decl,
243                               sizeof(**decl) * ((*num) + 1));
244         if(!newdecl) {
245             ERR("Error reallocating declarations array\n");
246             return FALSE;
247         }
248         *decl = newdecl;
249     }
250     (*decl)[*num].usage = usage;
251     (*decl)[*num].usage_idx = usage_idx;
252     (*decl)[*num].regnum = regnum;
253     (*decl)[*num].writemask = writemask;
254     (*num)++;
255
256     return TRUE;
257 }
258
259 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD regnum) {
260     unsigned int i;
261
262     if(!shader) return FALSE;
263
264     if(shader->num_samplers == 0) {
265         shader->samplers = asm_alloc(sizeof(*shader->samplers));
266         if(!shader->samplers) {
267             ERR("Error allocating samplers array\n");
268             return FALSE;
269         }
270     } else {
271         struct samplerdecl *newarray;
272
273         for(i = 0; i < shader->num_samplers; i++) {
274             if(shader->samplers[i].regnum == regnum) {
275                 WARN("Sampler %u already declared\n", regnum);
276                 /* This is not an error as far as the assembler is concerned.
277                  * Direct3D might refuse to load the compiled shader though
278                  */
279             }
280         }
281
282         newarray = asm_realloc(shader->samplers,
283                                sizeof(*shader->samplers) * (shader->num_samplers + 1));
284         if(!newarray) {
285             ERR("Error reallocating samplers array\n");
286             return FALSE;
287         }
288         shader->samplers = newarray;
289     }
290
291     shader->samplers[shader->num_samplers].type = samptype;
292     shader->samplers[shader->num_samplers].regnum = regnum;
293     shader->num_samplers++;
294     return TRUE;
295 }
296
297
298 /* shader bytecode buffer manipulation functions.
299  * allocate_buffer creates a new buffer structure, put_dword adds a new
300  * DWORD to the buffer. In the rare case of a memory allocation failure
301  * when trying to grow the buffer a flag is set in the buffer to mark it
302  * invalid. This avoids return value checking and passing in many places
303  */
304 static struct bytecode_buffer *allocate_buffer(void) {
305     struct bytecode_buffer *ret;
306
307     ret = asm_alloc(sizeof(*ret));
308     if(!ret) return NULL;
309
310     ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
311     ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
312     if(!ret->data) {
313         asm_free(ret);
314         return NULL;
315     }
316     ret->state = S_OK;
317     return ret;
318 }
319
320 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
321     if(FAILED(buffer->state)) return;
322
323     if(buffer->alloc_size == buffer->size) {
324         DWORD *newarray;
325         buffer->alloc_size *= 2;
326         newarray = asm_realloc(buffer->data,
327                                sizeof(DWORD) * buffer->alloc_size);
328         if(!newarray) {
329             ERR("Failed to grow the buffer data memory\n");
330             buffer->state = E_OUTOFMEMORY;
331             return;
332         }
333         buffer->data = newarray;
334     }
335     buffer->data[buffer->size++] = value;
336 }
337
338 /******************************************************
339  * Implementation of the writer functions starts here *
340  ******************************************************/
341 static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
342                                const struct declaration *decls, unsigned int num, DWORD type) {
343     DWORD i;
344     DWORD instr_dcl = D3DSIO_DCL;
345     DWORD token;
346
347     if(len) {
348         instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
349     }
350
351     for(i = 0; i < num; i++) {
352         /* Write the DCL instruction */
353         put_dword(buffer, instr_dcl);
354
355         /* Write the usage and index */
356         token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
357         token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
358         token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
359         put_dword(buffer, token);
360
361         /* Write the dest register */
362         token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
363         token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
364         token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL;
365         token |= decls[i].regnum & D3DSP_REGNUM_MASK;
366         put_dword(buffer, token);
367     }
368 }
369
370 static void write_const(struct constant **consts, int num, DWORD opcode, DWORD reg_type, struct bytecode_buffer *buffer, BOOL len) {
371     DWORD i;
372     DWORD instr_def = opcode;
373     const DWORD reg = (1<<31) |
374                       ((reg_type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
375                       ((reg_type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
376                       D3DSP_WRITEMASK_ALL;
377
378     if(len) {
379         if(opcode == D3DSIO_DEFB)
380             instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
381         else
382             instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
383     }
384
385     for(i = 0; i < num; i++) {
386         /* Write the DEF instruction */
387         put_dword(buffer, instr_def);
388
389         put_dword(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
390         put_dword(buffer, consts[i]->value[0].d);
391         if(opcode != D3DSIO_DEFB) {
392             put_dword(buffer, consts[i]->value[1].d);
393             put_dword(buffer, consts[i]->value[2].d);
394             put_dword(buffer, consts[i]->value[3].d);
395         }
396     }
397 }
398
399 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
400     write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
401 }
402
403 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
404     put_dword(buffer, D3DSIO_END);
405 }
406
407 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
408                           struct bytecode_buffer *buffer){
409     unsigned int i;
410     if(instr->has_predicate){
411         This->funcs->srcreg(This, &instr->predicate, buffer);
412     }
413     for(i = 0; i < instr->num_srcs; i++){
414         This->funcs->srcreg(This, &instr->src[i], buffer);
415     }
416 }
417
418 /* The length of an instruction consists of the destination register (if any),
419  * the number of source registers, the number of address registers used for
420  * indirect addressing, and optionally the predicate register
421  */
422 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
423     unsigned int i;
424     DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
425
426     if(dsts){
427         if(instr->dst.rel_reg) ret++;
428     }
429     for(i = 0; i < srcs; i++) {
430         if(instr->src[i].rel_reg) ret++;
431     }
432     return ret;
433 }
434
435 static void instr_handler(struct bc_writer *This,
436                           const struct instruction *instr,
437                           struct bytecode_buffer *buffer) {
438     DWORD token = d3d9_opcode(instr->opcode);
439     TRACE("token: %x\n", token);
440
441     This->funcs->opcode(This, instr, token, buffer);
442     if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
443     write_srcregs(This, instr, buffer);
444 }
445
446 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
447     write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
448 }
449
450 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
451     write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
452 }
453
454 static void sm_2_opcode(struct bc_writer *This,
455                         const struct instruction *instr,
456                         DWORD token, struct bytecode_buffer *buffer) {
457     /* From sm 2 onwards instruction length is encoded in the opcode field */
458     int dsts = instr->has_dst ? 1 : 0;
459     token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
460     if(instr->comptype)
461         token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
462     if(instr->has_predicate)
463         token |= D3DSHADER_INSTRUCTION_PREDICATED;
464     put_dword(buffer,token);
465 }
466
467 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
468     DWORD i;
469     DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
470     DWORD token;
471     const DWORD reg = (1<<31) |
472                       ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
473                       ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
474                       D3DSP_WRITEMASK_ALL;
475
476     for(i = 0; i < shader->num_samplers; i++) {
477         /* Write the DCL instruction */
478         put_dword(buffer, instr_dcl);
479         token = (1<<31);
480         /* Already shifted */
481         token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
482         put_dword(buffer, token);
483         put_dword(buffer, reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK));
484     }
485 }
486
487 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
488     /* Declare the shader type and version */
489     put_dword(buffer, This->version);
490
491     write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
492     write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT);
493     write_constF(shader, buffer, TRUE);
494     write_constB(shader, buffer, TRUE);
495     write_constI(shader, buffer, TRUE);
496     write_samplers(shader, buffer);
497     return;
498 }
499
500 static void sm_3_srcreg(struct bc_writer *This,
501                         const struct shader_reg *reg,
502                         struct bytecode_buffer *buffer) {
503     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
504     DWORD d3d9reg;
505
506     d3d9reg = d3d9_register(reg->type);
507     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
508     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
509     token |= reg->regnum & D3DSP_REGNUM_MASK;
510
511     token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
512     token |= d3d9_srcmod(reg->srcmod);
513
514     if(reg->rel_reg) {
515         if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
516             WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
517             This->state = E_INVALIDARG;
518             return;
519         }
520         if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
521            reg->rel_reg->type == BWRITERSPR_LOOP) &&
522            reg->rel_reg->regnum == 0) {
523             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
524         } else {
525             WARN("Unsupported relative addressing register\n");
526             This->state = E_INVALIDARG;
527             return;
528         }
529     }
530
531     put_dword(buffer, token);
532
533     /* vs_2_0 and newer write the register containing the index explicitly in the
534      * binary code
535      */
536     if(token & D3DVS_ADDRMODE_RELATIVE) {
537         sm_3_srcreg(This, reg->rel_reg, buffer);
538     }
539 }
540
541 static void sm_3_dstreg(struct bc_writer *This,
542                         const struct shader_reg *reg,
543                         struct bytecode_buffer *buffer,
544                         DWORD shift, DWORD mod) {
545     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
546     DWORD d3d9reg;
547
548     if(reg->rel_reg) {
549         if(This->version == BWRITERVS_VERSION(3, 0) &&
550            reg->type == BWRITERSPR_OUTPUT) {
551             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
552         } else {
553             WARN("Relative addressing not supported for this shader type or register type\n");
554             This->state = E_INVALIDARG;
555             return;
556         }
557     }
558
559     d3d9reg = d3d9_register(reg->type);
560     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
561     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
562     token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
563
564     token |= d3d9_dstmod(mod);
565
566     token |= d3d9_writemask(reg->writemask);
567     put_dword(buffer, token);
568
569     /* vs_2_0 and newer write the register containing the index explicitly in the
570      * binary code
571      */
572     if(token & D3DVS_ADDRMODE_RELATIVE) {
573         sm_3_srcreg(This, reg->rel_reg, buffer);
574     }
575 }
576
577 static const struct instr_handler_table vs_3_handlers[] = {
578     {BWRITERSIO_ADD,            instr_handler},
579     {BWRITERSIO_NOP,            instr_handler},
580     {BWRITERSIO_MOV,            instr_handler},
581     {BWRITERSIO_SUB,            instr_handler},
582     {BWRITERSIO_MAD,            instr_handler},
583     {BWRITERSIO_MUL,            instr_handler},
584     {BWRITERSIO_RCP,            instr_handler},
585     {BWRITERSIO_RSQ,            instr_handler},
586     {BWRITERSIO_DP3,            instr_handler},
587     {BWRITERSIO_DP4,            instr_handler},
588     {BWRITERSIO_MIN,            instr_handler},
589     {BWRITERSIO_MAX,            instr_handler},
590     {BWRITERSIO_SLT,            instr_handler},
591     {BWRITERSIO_SGE,            instr_handler},
592     {BWRITERSIO_ABS,            instr_handler},
593     {BWRITERSIO_EXP,            instr_handler},
594     {BWRITERSIO_LOG,            instr_handler},
595     {BWRITERSIO_EXPP,           instr_handler},
596     {BWRITERSIO_LOGP,           instr_handler},
597     {BWRITERSIO_DST,            instr_handler},
598     {BWRITERSIO_LRP,            instr_handler},
599     {BWRITERSIO_FRC,            instr_handler},
600     {BWRITERSIO_CRS,            instr_handler},
601     {BWRITERSIO_SGN,            instr_handler},
602     {BWRITERSIO_NRM,            instr_handler},
603     {BWRITERSIO_SINCOS,         instr_handler},
604     {BWRITERSIO_M4x4,           instr_handler},
605     {BWRITERSIO_M4x3,           instr_handler},
606     {BWRITERSIO_M3x4,           instr_handler},
607     {BWRITERSIO_M3x3,           instr_handler},
608     {BWRITERSIO_M3x2,           instr_handler},
609     {BWRITERSIO_LIT,            instr_handler},
610     {BWRITERSIO_POW,            instr_handler},
611     {BWRITERSIO_MOVA,           instr_handler},
612
613     {BWRITERSIO_CALL,           instr_handler},
614     {BWRITERSIO_CALLNZ,         instr_handler},
615     {BWRITERSIO_REP,            instr_handler},
616     {BWRITERSIO_ENDREP,         instr_handler},
617     {BWRITERSIO_IF,             instr_handler},
618     {BWRITERSIO_LABEL,          instr_handler},
619     {BWRITERSIO_IFC,            instr_handler},
620     {BWRITERSIO_ELSE,           instr_handler},
621     {BWRITERSIO_ENDIF,          instr_handler},
622     {BWRITERSIO_BREAK,          instr_handler},
623     {BWRITERSIO_BREAKC,         instr_handler},
624     {BWRITERSIO_LOOP,           instr_handler},
625     {BWRITERSIO_RET,            instr_handler},
626     {BWRITERSIO_ENDLOOP,        instr_handler},
627
628     {BWRITERSIO_SETP,           instr_handler},
629     {BWRITERSIO_BREAKP,         instr_handler},
630     {BWRITERSIO_TEXLDL,         instr_handler},
631
632     {BWRITERSIO_END,            NULL},
633 };
634
635 static const struct bytecode_backend vs_3_backend = {
636     sm_3_header,
637     end,
638     sm_3_srcreg,
639     sm_3_dstreg,
640     sm_2_opcode,
641     vs_3_handlers
642 };
643
644 static const struct instr_handler_table ps_3_handlers[] = {
645     {BWRITERSIO_ADD,            instr_handler},
646     {BWRITERSIO_NOP,            instr_handler},
647     {BWRITERSIO_MOV,            instr_handler},
648     {BWRITERSIO_SUB,            instr_handler},
649     {BWRITERSIO_MAD,            instr_handler},
650     {BWRITERSIO_MUL,            instr_handler},
651     {BWRITERSIO_RCP,            instr_handler},
652     {BWRITERSIO_RSQ,            instr_handler},
653     {BWRITERSIO_DP3,            instr_handler},
654     {BWRITERSIO_DP4,            instr_handler},
655     {BWRITERSIO_MIN,            instr_handler},
656     {BWRITERSIO_MAX,            instr_handler},
657     {BWRITERSIO_ABS,            instr_handler},
658     {BWRITERSIO_EXP,            instr_handler},
659     {BWRITERSIO_LOG,            instr_handler},
660     {BWRITERSIO_EXPP,           instr_handler},
661     {BWRITERSIO_LOGP,           instr_handler},
662     {BWRITERSIO_LRP,            instr_handler},
663     {BWRITERSIO_FRC,            instr_handler},
664     {BWRITERSIO_CRS,            instr_handler},
665     {BWRITERSIO_NRM,            instr_handler},
666     {BWRITERSIO_SINCOS,         instr_handler},
667     {BWRITERSIO_M4x4,           instr_handler},
668     {BWRITERSIO_M4x3,           instr_handler},
669     {BWRITERSIO_M3x4,           instr_handler},
670     {BWRITERSIO_M3x3,           instr_handler},
671     {BWRITERSIO_M3x2,           instr_handler},
672     {BWRITERSIO_POW,            instr_handler},
673     {BWRITERSIO_DP2ADD,         instr_handler},
674     {BWRITERSIO_CMP,            instr_handler},
675
676     {BWRITERSIO_CALL,           instr_handler},
677     {BWRITERSIO_CALLNZ,         instr_handler},
678     {BWRITERSIO_REP,            instr_handler},
679     {BWRITERSIO_ENDREP,         instr_handler},
680     {BWRITERSIO_IF,             instr_handler},
681     {BWRITERSIO_LABEL,          instr_handler},
682     {BWRITERSIO_IFC,            instr_handler},
683     {BWRITERSIO_ELSE,           instr_handler},
684     {BWRITERSIO_ENDIF,          instr_handler},
685     {BWRITERSIO_BREAK,          instr_handler},
686     {BWRITERSIO_BREAKC,         instr_handler},
687     {BWRITERSIO_LOOP,           instr_handler},
688     {BWRITERSIO_RET,            instr_handler},
689     {BWRITERSIO_ENDLOOP,        instr_handler},
690
691     {BWRITERSIO_SETP,           instr_handler},
692     {BWRITERSIO_BREAKP,         instr_handler},
693     {BWRITERSIO_TEXLDL,         instr_handler},
694
695     {BWRITERSIO_TEX,            instr_handler},
696     {BWRITERSIO_TEXLDP,         instr_handler},
697     {BWRITERSIO_TEXLDB,         instr_handler},
698     {BWRITERSIO_TEXKILL,        instr_handler},
699     {BWRITERSIO_DSX,            instr_handler},
700     {BWRITERSIO_DSY,            instr_handler},
701     {BWRITERSIO_TEXLDD,         instr_handler},
702
703     {BWRITERSIO_END,            NULL},
704 };
705
706 static const struct bytecode_backend ps_3_backend = {
707     sm_3_header,
708     end,
709     sm_3_srcreg,
710     sm_3_dstreg,
711     sm_2_opcode,
712     ps_3_handlers
713 };
714
715 static void init_vs30_dx9_writer(struct bc_writer *writer) {
716     TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
717     writer->funcs = &vs_3_backend;
718 }
719
720 static void init_ps30_dx9_writer(struct bc_writer *writer) {
721     TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
722     writer->funcs = &ps_3_backend;
723 }
724
725 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
726     struct bc_writer *ret = asm_alloc(sizeof(*ret));
727
728     if(!ret) {
729         WARN("Failed to allocate a bytecode writer instance\n");
730         return NULL;
731     }
732
733     switch(version) {
734         case BWRITERVS_VERSION(1, 0):
735             if(dxversion != 9) {
736                 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
737                 goto fail;
738             }
739             /* TODO: Set the appropriate writer backend */
740             break;
741         case BWRITERVS_VERSION(1, 1):
742             if(dxversion != 9) {
743                 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
744                 goto fail;
745             }
746             /* TODO: Set the appropriate writer backend */
747             break;
748         case BWRITERVS_VERSION(2, 0):
749             if(dxversion != 9) {
750                 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
751                 goto fail;
752             }
753             /* TODO: Set the appropriate writer backend */
754             break;
755         case BWRITERVS_VERSION(2, 1):
756             if(dxversion != 9) {
757                 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
758                 goto fail;
759             }
760             /* TODO: Set the appropriate writer backend */
761             break;
762         case BWRITERVS_VERSION(3, 0):
763             if(dxversion != 9) {
764                 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
765                 goto fail;
766             }
767             init_vs30_dx9_writer(ret);
768             break;
769
770         case BWRITERPS_VERSION(1, 0):
771             if(dxversion != 9) {
772                 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
773                 goto fail;
774             }
775             /* TODO: Set the appropriate writer backend */
776             break;
777         case BWRITERPS_VERSION(1, 1):
778             if(dxversion != 9) {
779                 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
780                 goto fail;
781             }
782             /* TODO: Set the appropriate writer backend */
783             break;
784         case BWRITERPS_VERSION(1, 2):
785             if(dxversion != 9) {
786                 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
787                 goto fail;
788             }
789             /* TODO: Set the appropriate writer backend */
790             break;
791         case BWRITERPS_VERSION(1, 3):
792             if(dxversion != 9) {
793                 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
794                 goto fail;
795             }
796             /* TODO: Set the appropriate writer backend */
797             break;
798         case BWRITERPS_VERSION(1, 4):
799             if(dxversion != 9) {
800                 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
801                 goto fail;
802             }
803             /* TODO: Set the appropriate writer backend */
804             break;
805
806         case BWRITERPS_VERSION(2, 0):
807             if(dxversion != 9) {
808                 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
809                 goto fail;
810             }
811             /* TODO: Set the appropriate writer backend */
812             break;
813
814         case BWRITERPS_VERSION(2, 1):
815             if(dxversion != 9) {
816                 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
817                 goto fail;
818             }
819             /* TODO: Set the appropriate writer backend */
820             break;
821
822         case BWRITERPS_VERSION(3, 0):
823             if(dxversion != 9) {
824                 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
825                 goto fail;
826             }
827             init_ps30_dx9_writer(ret);
828             break;
829
830         default:
831             WARN("Unexpected shader version requested: %08x\n", version);
832             goto fail;
833     }
834     ret->version = version;
835     return ret;
836
837 fail:
838     asm_free(ret);
839     return NULL;
840 }
841
842 static HRESULT call_instr_handler(struct bc_writer *writer,
843                                   const struct instruction *instr,
844                                   struct bytecode_buffer *buffer) {
845     DWORD i=0;
846
847     while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
848         if(instr->opcode == writer->funcs->instructions[i].opcode) {
849             if(!writer->funcs->instructions[i].func) {
850                 WARN("Opcode %u not supported by this profile\n", instr->opcode);
851                 return E_INVALIDARG;
852             }
853             writer->funcs->instructions[i].func(writer, instr, buffer);
854             return S_OK;
855         }
856         i++;
857     }
858
859     FIXME("Unhandled instruction %u\n", instr->opcode);
860     return E_INVALIDARG;
861 }
862
863 /* SlWriteBytecode (wineshader.@)
864  *
865  * Writes shader version specific bytecode from the shader passed in.
866  * The returned bytecode can be passed to the Direct3D runtime like
867  * IDirect3DDevice9::Create*Shader.
868  *
869  * Parameters:
870  *  shader: Shader to translate into bytecode
871  *  version: Shader version to generate(d3d version token)
872  *  dxversion: DirectX version the code targets
873  *  result: the resulting shader bytecode
874  *
875  * Return values:
876  *  S_OK on success
877  */
878 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
879     struct bc_writer *writer;
880     struct bytecode_buffer *buffer = NULL;
881     HRESULT hr;
882     unsigned int i;
883
884     if(!shader){
885         ERR("NULL shader structure, aborting\n");
886         return E_FAIL;
887     }
888     writer = create_writer(shader->version, dxversion);
889     *result = NULL;
890
891     if(!writer) {
892         WARN("Could not create a bytecode writer instance. Either unsupported version\n");
893         WARN("or out of memory\n");
894         hr = E_FAIL;
895         goto error;
896     }
897
898     buffer = allocate_buffer();
899     if(!buffer) {
900         WARN("Failed to allocate a buffer for the shader bytecode\n");
901         hr = E_FAIL;
902         goto error;
903     }
904
905     writer->funcs->header(writer, shader, buffer);
906     if(FAILED(writer->state)) {
907         hr = writer->state;
908         goto error;
909     }
910
911     for(i = 0; i < shader->num_instrs; i++) {
912         hr = call_instr_handler(writer, shader->instr[i], buffer);
913         if(FAILED(hr)) {
914             goto error;
915         }
916     }
917
918     if(FAILED(writer->state)) {
919         hr = writer->state;
920         goto error;
921     }
922
923     writer->funcs->end(writer, shader, buffer);
924
925     if(FAILED(buffer->state)) {
926         hr = buffer->state;
927         goto error;
928     }
929
930     /* Cut off unneeded memory from the result buffer */
931     *result = asm_realloc(buffer->data,
932                          sizeof(DWORD) * buffer->size);
933     if(!*result) {
934         *result = buffer->data;
935     }
936     buffer->data = NULL;
937     hr = S_OK;
938
939 error:
940     if(buffer) {
941         asm_free(buffer->data);
942         asm_free(buffer);
943     }
944     asm_free(writer);
945     return hr;
946 }
947
948 void SlDeleteShader(struct bwriter_shader *shader) {
949     unsigned int i, j;
950
951     TRACE("Deleting shader %p\n", shader);
952
953     for(i = 0; i < shader->num_cf; i++) {
954         asm_free(shader->constF[i]);
955     }
956     asm_free(shader->constF);
957     for(i = 0; i < shader->num_ci; i++) {
958         asm_free(shader->constI[i]);
959     }
960     asm_free(shader->constI);
961     for(i = 0; i < shader->num_cb; i++) {
962         asm_free(shader->constB[i]);
963     }
964     asm_free(shader->constB);
965
966     asm_free(shader->inputs);
967     asm_free(shader->outputs);
968     asm_free(shader->samplers);
969
970     for(i = 0; i < shader->num_instrs; i++) {
971         for(j = 0; j < shader->instr[i]->num_srcs; j++) {
972             asm_free(shader->instr[i]->src[j].rel_reg);
973         }
974         asm_free(shader->instr[i]->src);
975         asm_free(shader->instr[i]);
976     }
977     asm_free(shader->instr);
978
979     asm_free(shader);
980 }