d3dx9: Add other flow control instructions 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 /* shader bytecode buffer manipulation functions.
108  * allocate_buffer creates a new buffer structure, put_dword adds a new
109  * DWORD to the buffer. In the rare case of a memory allocation failure
110  * when trying to grow the buffer a flag is set in the buffer to mark it
111  * invalid. This avoids return value checking and passing in many places
112  */
113 static struct bytecode_buffer *allocate_buffer(void) {
114     struct bytecode_buffer *ret;
115
116     ret = asm_alloc(sizeof(*ret));
117     if(!ret) return NULL;
118
119     ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
120     ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
121     if(!ret->data) {
122         asm_free(ret);
123         return NULL;
124     }
125     ret->state = S_OK;
126     return ret;
127 }
128
129 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
130     if(FAILED(buffer->state)) return;
131
132     if(buffer->alloc_size == buffer->size) {
133         DWORD *newarray;
134         buffer->alloc_size *= 2;
135         newarray = asm_realloc(buffer->data,
136                                sizeof(DWORD) * buffer->alloc_size);
137         if(!newarray) {
138             ERR("Failed to grow the buffer data memory\n");
139             buffer->state = E_OUTOFMEMORY;
140             return;
141         }
142         buffer->data = newarray;
143     }
144     buffer->data[buffer->size++] = value;
145 }
146
147 /******************************************************
148  * Implementation of the writer functions starts here *
149  ******************************************************/
150 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
151     put_dword(buffer, D3DSIO_END);
152 }
153
154 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
155                           struct bytecode_buffer *buffer){
156     unsigned int i;
157     if(instr->has_predicate){
158         This->funcs->srcreg(This, &instr->predicate, buffer);
159     }
160     for(i = 0; i < instr->num_srcs; i++){
161         This->funcs->srcreg(This, &instr->src[i], buffer);
162     }
163 }
164
165 /* The length of an instruction consists of the destination register (if any),
166  * the number of source registers, the number of address registers used for
167  * indirect addressing, and optionally the predicate register
168  */
169 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
170     unsigned int i;
171     DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
172
173     if(dsts){
174         if(instr->dst.rel_reg) ret++;
175     }
176     for(i = 0; i < srcs; i++) {
177         if(instr->src[i].rel_reg) ret++;
178     }
179     return ret;
180 }
181
182 static void instr_handler(struct bc_writer *This,
183                           const struct instruction *instr,
184                           struct bytecode_buffer *buffer) {
185     DWORD token = d3d9_opcode(instr->opcode);
186     TRACE("token: %x\n", token);
187
188     This->funcs->opcode(This, instr, token, buffer);
189     if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
190     write_srcregs(This, instr, buffer);
191 }
192
193 static void sm_2_opcode(struct bc_writer *This,
194                         const struct instruction *instr,
195                         DWORD token, struct bytecode_buffer *buffer) {
196     /* From sm 2 onwards instruction length is encoded in the opcode field */
197     int dsts = instr->has_dst ? 1 : 0;
198     token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
199     if(instr->comptype)
200         token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
201     put_dword(buffer,token);
202 }
203
204 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
205     /* Declare the shader type and version */
206     put_dword(buffer, This->version);
207     return;
208 }
209
210 static void sm_3_srcreg(struct bc_writer *This,
211                         const struct shader_reg *reg,
212                         struct bytecode_buffer *buffer) {
213     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
214     DWORD d3d9reg;
215
216     d3d9reg = d3d9_register(reg->type);
217     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
218     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
219     token |= reg->regnum & D3DSP_REGNUM_MASK;
220
221     token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
222     token |= d3d9_srcmod(reg->srcmod);
223
224     if(reg->rel_reg) {
225         if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
226             WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
227             This->state = E_INVALIDARG;
228             return;
229         }
230         if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
231            reg->rel_reg->type == BWRITERSPR_LOOP) &&
232            reg->rel_reg->regnum == 0) {
233             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
234         } else {
235             WARN("Unsupported relative addressing register\n");
236             This->state = E_INVALIDARG;
237             return;
238         }
239     }
240
241     put_dword(buffer, token);
242
243     /* vs_2_0 and newer write the register containing the index explicitly in the
244      * binary code
245      */
246     if(token & D3DVS_ADDRMODE_RELATIVE) {
247         sm_3_srcreg(This, reg->rel_reg, buffer);
248     }
249 }
250
251 static void sm_3_dstreg(struct bc_writer *This,
252                         const struct shader_reg *reg,
253                         struct bytecode_buffer *buffer,
254                         DWORD shift, DWORD mod) {
255     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
256     DWORD d3d9reg;
257
258     if(reg->rel_reg) {
259         if(This->version == BWRITERVS_VERSION(3, 0) &&
260            reg->type == BWRITERSPR_OUTPUT) {
261             token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
262         } else {
263             WARN("Relative addressing not supported for this shader type or register type\n");
264             This->state = E_INVALIDARG;
265             return;
266         }
267     }
268
269     d3d9reg = d3d9_register(reg->type);
270     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
271     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
272     token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
273
274     token |= d3d9_dstmod(mod);
275
276     token |= d3d9_writemask(reg->writemask);
277     put_dword(buffer, token);
278
279     /* vs_2_0 and newer write the register containing the index explicitly in the
280      * binary code
281      */
282     if(token & D3DVS_ADDRMODE_RELATIVE) {
283         sm_3_srcreg(This, reg->rel_reg, buffer);
284     }
285 }
286
287 static const struct instr_handler_table vs_3_handlers[] = {
288     {BWRITERSIO_ADD,            instr_handler},
289     {BWRITERSIO_NOP,            instr_handler},
290     {BWRITERSIO_MOV,            instr_handler},
291     {BWRITERSIO_SUB,            instr_handler},
292     {BWRITERSIO_MAD,            instr_handler},
293     {BWRITERSIO_MUL,            instr_handler},
294     {BWRITERSIO_RCP,            instr_handler},
295     {BWRITERSIO_RSQ,            instr_handler},
296     {BWRITERSIO_DP3,            instr_handler},
297     {BWRITERSIO_DP4,            instr_handler},
298     {BWRITERSIO_MIN,            instr_handler},
299     {BWRITERSIO_MAX,            instr_handler},
300     {BWRITERSIO_SLT,            instr_handler},
301     {BWRITERSIO_SGE,            instr_handler},
302     {BWRITERSIO_ABS,            instr_handler},
303     {BWRITERSIO_EXP,            instr_handler},
304     {BWRITERSIO_LOG,            instr_handler},
305     {BWRITERSIO_EXPP,           instr_handler},
306     {BWRITERSIO_LOGP,           instr_handler},
307     {BWRITERSIO_DST,            instr_handler},
308     {BWRITERSIO_LRP,            instr_handler},
309     {BWRITERSIO_FRC,            instr_handler},
310     {BWRITERSIO_CRS,            instr_handler},
311     {BWRITERSIO_SGN,            instr_handler},
312     {BWRITERSIO_NRM,            instr_handler},
313     {BWRITERSIO_SINCOS,         instr_handler},
314     {BWRITERSIO_M4x4,           instr_handler},
315     {BWRITERSIO_M4x3,           instr_handler},
316     {BWRITERSIO_M3x4,           instr_handler},
317     {BWRITERSIO_M3x3,           instr_handler},
318     {BWRITERSIO_M3x2,           instr_handler},
319     {BWRITERSIO_LIT,            instr_handler},
320     {BWRITERSIO_POW,            instr_handler},
321     {BWRITERSIO_MOVA,           instr_handler},
322
323     {BWRITERSIO_CALL,           instr_handler},
324     {BWRITERSIO_CALLNZ,         instr_handler},
325     {BWRITERSIO_REP,            instr_handler},
326     {BWRITERSIO_ENDREP,         instr_handler},
327     {BWRITERSIO_IF,             instr_handler},
328     {BWRITERSIO_LABEL,          instr_handler},
329     {BWRITERSIO_IFC,            instr_handler},
330     {BWRITERSIO_ELSE,           instr_handler},
331     {BWRITERSIO_ENDIF,          instr_handler},
332     {BWRITERSIO_BREAK,          instr_handler},
333     {BWRITERSIO_BREAKC,         instr_handler},
334     {BWRITERSIO_LOOP,           instr_handler},
335     {BWRITERSIO_RET,            instr_handler},
336     {BWRITERSIO_ENDLOOP,        instr_handler},
337
338     {BWRITERSIO_TEXLDL,         instr_handler},
339
340     {BWRITERSIO_END,            NULL},
341 };
342
343 static const struct bytecode_backend vs_3_backend = {
344     sm_3_header,
345     end,
346     sm_3_srcreg,
347     sm_3_dstreg,
348     sm_2_opcode,
349     vs_3_handlers
350 };
351
352 static void init_vs30_dx9_writer(struct bc_writer *writer) {
353     TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
354     writer->funcs = &vs_3_backend;
355 }
356
357 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
358     struct bc_writer *ret = asm_alloc(sizeof(*ret));
359
360     if(!ret) {
361         WARN("Failed to allocate a bytecode writer instance\n");
362         return NULL;
363     }
364
365     switch(version) {
366         case BWRITERVS_VERSION(1, 0):
367             if(dxversion != 9) {
368                 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
369                 goto fail;
370             }
371             /* TODO: Set the appropriate writer backend */
372             break;
373         case BWRITERVS_VERSION(1, 1):
374             if(dxversion != 9) {
375                 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
376                 goto fail;
377             }
378             /* TODO: Set the appropriate writer backend */
379             break;
380         case BWRITERVS_VERSION(2, 0):
381             if(dxversion != 9) {
382                 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
383                 goto fail;
384             }
385             /* TODO: Set the appropriate writer backend */
386             break;
387         case BWRITERVS_VERSION(2, 1):
388             if(dxversion != 9) {
389                 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
390                 goto fail;
391             }
392             /* TODO: Set the appropriate writer backend */
393             break;
394         case BWRITERVS_VERSION(3, 0):
395             if(dxversion != 9) {
396                 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
397                 goto fail;
398             }
399             init_vs30_dx9_writer(ret);
400             break;
401
402         case BWRITERPS_VERSION(1, 0):
403             if(dxversion != 9) {
404                 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
405                 goto fail;
406             }
407             /* TODO: Set the appropriate writer backend */
408             break;
409         case BWRITERPS_VERSION(1, 1):
410             if(dxversion != 9) {
411                 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
412                 goto fail;
413             }
414             /* TODO: Set the appropriate writer backend */
415             break;
416         case BWRITERPS_VERSION(1, 2):
417             if(dxversion != 9) {
418                 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
419                 goto fail;
420             }
421             /* TODO: Set the appropriate writer backend */
422             break;
423         case BWRITERPS_VERSION(1, 3):
424             if(dxversion != 9) {
425                 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
426                 goto fail;
427             }
428             /* TODO: Set the appropriate writer backend */
429             break;
430         case BWRITERPS_VERSION(1, 4):
431             if(dxversion != 9) {
432                 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
433                 goto fail;
434             }
435             /* TODO: Set the appropriate writer backend */
436             break;
437
438         case BWRITERPS_VERSION(2, 0):
439             if(dxversion != 9) {
440                 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
441                 goto fail;
442             }
443             /* TODO: Set the appropriate writer backend */
444             break;
445
446         case BWRITERPS_VERSION(2, 1):
447             if(dxversion != 9) {
448                 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
449                 goto fail;
450             }
451             /* TODO: Set the appropriate writer backend */
452             break;
453
454         case BWRITERPS_VERSION(3, 0):
455             if(dxversion != 9) {
456                 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
457                 goto fail;
458             }
459             /* TODO: Set the appropriate writer backend */
460             break;
461
462         default:
463             WARN("Unexpected shader version requested: %08x\n", version);
464             goto fail;
465     }
466     ret->version = version;
467     return ret;
468
469 fail:
470     asm_free(ret);
471     return NULL;
472 }
473
474 static HRESULT call_instr_handler(struct bc_writer *writer,
475                                   const struct instruction *instr,
476                                   struct bytecode_buffer *buffer) {
477     DWORD i=0;
478
479     while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
480         if(instr->opcode == writer->funcs->instructions[i].opcode) {
481             if(!writer->funcs->instructions[i].func) {
482                 WARN("Opcode %u not supported by this profile\n", instr->opcode);
483                 return E_INVALIDARG;
484             }
485             writer->funcs->instructions[i].func(writer, instr, buffer);
486             return S_OK;
487         }
488         i++;
489     }
490
491     FIXME("Unhandled instruction %u\n", instr->opcode);
492     return E_INVALIDARG;
493 }
494
495 /* SlWriteBytecode (wineshader.@)
496  *
497  * Writes shader version specific bytecode from the shader passed in.
498  * The returned bytecode can be passed to the Direct3D runtime like
499  * IDirect3DDevice9::Create*Shader.
500  *
501  * Parameters:
502  *  shader: Shader to translate into bytecode
503  *  version: Shader version to generate(d3d version token)
504  *  dxversion: DirectX version the code targets
505  *  result: the resulting shader bytecode
506  *
507  * Return values:
508  *  S_OK on success
509  */
510 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
511     struct bc_writer *writer;
512     struct bytecode_buffer *buffer = NULL;
513     HRESULT hr;
514     unsigned int i;
515
516     if(!shader){
517         ERR("NULL shader structure, aborting\n");
518         return E_FAIL;
519     }
520     writer = create_writer(shader->version, dxversion);
521     *result = NULL;
522
523     if(!writer) {
524         WARN("Could not create a bytecode writer instance. Either unsupported version\n");
525         WARN("or out of memory\n");
526         hr = E_FAIL;
527         goto error;
528     }
529
530     buffer = allocate_buffer();
531     if(!buffer) {
532         WARN("Failed to allocate a buffer for the shader bytecode\n");
533         hr = E_FAIL;
534         goto error;
535     }
536
537     writer->funcs->header(writer, shader, buffer);
538     if(FAILED(writer->state)) {
539         hr = writer->state;
540         goto error;
541     }
542
543     for(i = 0; i < shader->num_instrs; i++) {
544         hr = call_instr_handler(writer, shader->instr[i], buffer);
545         if(FAILED(hr)) {
546             goto error;
547         }
548     }
549
550     if(FAILED(writer->state)) {
551         hr = writer->state;
552         goto error;
553     }
554
555     writer->funcs->end(writer, shader, buffer);
556
557     if(FAILED(buffer->state)) {
558         hr = buffer->state;
559         goto error;
560     }
561
562     /* Cut off unneeded memory from the result buffer */
563     *result = asm_realloc(buffer->data,
564                          sizeof(DWORD) * buffer->size);
565     if(!*result) {
566         *result = buffer->data;
567     }
568     buffer->data = NULL;
569     hr = S_OK;
570
571 error:
572     if(buffer) {
573         asm_free(buffer->data);
574         asm_free(buffer);
575     }
576     asm_free(writer);
577     return hr;
578 }
579
580 void SlDeleteShader(struct bwriter_shader *shader) {
581     unsigned int i, j;
582
583     TRACE("Deleting shader %p\n", shader);
584
585     for(i = 0; i < shader->num_cf; i++) {
586         asm_free(shader->constF[i]);
587     }
588     asm_free(shader->constF);
589     for(i = 0; i < shader->num_ci; i++) {
590         asm_free(shader->constI[i]);
591     }
592     asm_free(shader->constI);
593     for(i = 0; i < shader->num_cb; i++) {
594         asm_free(shader->constB[i]);
595     }
596     asm_free(shader->constB);
597
598     asm_free(shader->inputs);
599     asm_free(shader->outputs);
600     asm_free(shader->samplers);
601
602     for(i = 0; i < shader->num_instrs; i++) {
603         for(j = 0; j < shader->instr[i]->num_srcs; j++) {
604             asm_free(shader->instr[i]->src[j].rel_reg);
605         }
606         asm_free(shader->instr[i]->src);
607         asm_free(shader->instr[i]);
608     }
609     asm_free(shader->instr);
610
611     asm_free(shader);
612 }