comctl32: Add support for alpha blending in ImageList_DrawIndirect.
[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     put_dword(buffer,token);
200 }
201
202 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
203     /* Declare the shader type and version */
204     put_dword(buffer, This->version);
205     return;
206 }
207
208 static void sm_3_srcreg(struct bc_writer *This,
209                         const struct shader_reg *reg,
210                         struct bytecode_buffer *buffer) {
211     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
212     DWORD d3d9reg;
213
214     d3d9reg = d3d9_register(reg->type);
215     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
216     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
217     token |= reg->regnum & D3DSP_REGNUM_MASK;
218
219     token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
220     token |= d3d9_srcmod(reg->srcmod);
221
222     put_dword(buffer, token);
223 }
224
225 static void sm_3_dstreg(struct bc_writer *This,
226                         const struct shader_reg *reg,
227                         struct bytecode_buffer *buffer,
228                         DWORD shift, DWORD mod) {
229     DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
230     DWORD d3d9reg;
231
232     d3d9reg = d3d9_register(reg->type);
233     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
234     token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
235     token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
236
237     token |= d3d9_dstmod(mod);
238
239     token |= d3d9_writemask(reg->writemask);
240     put_dword(buffer, token);
241 }
242
243 static const struct instr_handler_table vs_3_handlers[] = {
244     {BWRITERSIO_MOV,            instr_handler},
245     {BWRITERSIO_END,            NULL},
246 };
247
248 static const struct bytecode_backend vs_3_backend = {
249     sm_3_header,
250     end,
251     sm_3_srcreg,
252     sm_3_dstreg,
253     sm_2_opcode,
254     vs_3_handlers
255 };
256
257 static void init_vs30_dx9_writer(struct bc_writer *writer) {
258     TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
259     writer->funcs = &vs_3_backend;
260 }
261
262 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
263     struct bc_writer *ret = asm_alloc(sizeof(*ret));
264
265     if(!ret) {
266         WARN("Failed to allocate a bytecode writer instance\n");
267         return NULL;
268     }
269
270     switch(version) {
271         case BWRITERVS_VERSION(1, 0):
272             if(dxversion != 9) {
273                 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
274                 goto fail;
275             }
276             /* TODO: Set the appropriate writer backend */
277             break;
278         case BWRITERVS_VERSION(1, 1):
279             if(dxversion != 9) {
280                 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
281                 goto fail;
282             }
283             /* TODO: Set the appropriate writer backend */
284             break;
285         case BWRITERVS_VERSION(2, 0):
286             if(dxversion != 9) {
287                 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
288                 goto fail;
289             }
290             /* TODO: Set the appropriate writer backend */
291             break;
292         case BWRITERVS_VERSION(2, 1):
293             if(dxversion != 9) {
294                 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
295                 goto fail;
296             }
297             /* TODO: Set the appropriate writer backend */
298             break;
299         case BWRITERVS_VERSION(3, 0):
300             if(dxversion != 9) {
301                 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
302                 goto fail;
303             }
304             init_vs30_dx9_writer(ret);
305             break;
306
307         case BWRITERPS_VERSION(1, 0):
308             if(dxversion != 9) {
309                 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
310                 goto fail;
311             }
312             /* TODO: Set the appropriate writer backend */
313             break;
314         case BWRITERPS_VERSION(1, 1):
315             if(dxversion != 9) {
316                 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
317                 goto fail;
318             }
319             /* TODO: Set the appropriate writer backend */
320             break;
321         case BWRITERPS_VERSION(1, 2):
322             if(dxversion != 9) {
323                 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
324                 goto fail;
325             }
326             /* TODO: Set the appropriate writer backend */
327             break;
328         case BWRITERPS_VERSION(1, 3):
329             if(dxversion != 9) {
330                 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
331                 goto fail;
332             }
333             /* TODO: Set the appropriate writer backend */
334             break;
335         case BWRITERPS_VERSION(1, 4):
336             if(dxversion != 9) {
337                 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
338                 goto fail;
339             }
340             /* TODO: Set the appropriate writer backend */
341             break;
342
343         case BWRITERPS_VERSION(2, 0):
344             if(dxversion != 9) {
345                 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
346                 goto fail;
347             }
348             /* TODO: Set the appropriate writer backend */
349             break;
350
351         case BWRITERPS_VERSION(2, 1):
352             if(dxversion != 9) {
353                 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
354                 goto fail;
355             }
356             /* TODO: Set the appropriate writer backend */
357             break;
358
359         case BWRITERPS_VERSION(3, 0):
360             if(dxversion != 9) {
361                 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
362                 goto fail;
363             }
364             /* TODO: Set the appropriate writer backend */
365             break;
366
367         default:
368             WARN("Unexpected shader version requested: %08x\n", version);
369             goto fail;
370     }
371     ret->version = version;
372     return ret;
373
374 fail:
375     asm_free(ret);
376     return NULL;
377 }
378
379 static HRESULT call_instr_handler(struct bc_writer *writer,
380                                   const struct instruction *instr,
381                                   struct bytecode_buffer *buffer) {
382     DWORD i=0;
383
384     while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
385         if(instr->opcode == writer->funcs->instructions[i].opcode) {
386             if(!writer->funcs->instructions[i].func) {
387                 WARN("Opcode %u not supported by this profile\n", instr->opcode);
388                 return E_INVALIDARG;
389             }
390             writer->funcs->instructions[i].func(writer, instr, buffer);
391             return S_OK;
392         }
393         i++;
394     }
395
396     FIXME("Unhandled instruction %u\n", instr->opcode);
397     return E_INVALIDARG;
398 }
399
400 /* SlWriteBytecode (wineshader.@)
401  *
402  * Writes shader version specific bytecode from the shader passed in.
403  * The returned bytecode can be passed to the Direct3D runtime like
404  * IDirect3DDevice9::Create*Shader.
405  *
406  * Parameters:
407  *  shader: Shader to translate into bytecode
408  *  version: Shader version to generate(d3d version token)
409  *  dxversion: DirectX version the code targets
410  *  result: the resulting shader bytecode
411  *
412  * Return values:
413  *  S_OK on success
414  */
415 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
416     struct bc_writer *writer;
417     struct bytecode_buffer *buffer = NULL;
418     HRESULT hr;
419     unsigned int i;
420
421     if(!shader){
422         ERR("NULL shader structure, aborting\n");
423         return E_FAIL;
424     }
425     writer = create_writer(shader->version, dxversion);
426     *result = NULL;
427
428     if(!writer) {
429         WARN("Could not create a bytecode writer instance. Either unsupported version\n");
430         WARN("or out of memory\n");
431         hr = E_FAIL;
432         goto error;
433     }
434
435     buffer = allocate_buffer();
436     if(!buffer) {
437         WARN("Failed to allocate a buffer for the shader bytecode\n");
438         hr = E_FAIL;
439         goto error;
440     }
441
442     writer->funcs->header(writer, shader, buffer);
443     if(FAILED(writer->state)) {
444         hr = writer->state;
445         goto error;
446     }
447
448     for(i = 0; i < shader->num_instrs; i++) {
449         hr = call_instr_handler(writer, shader->instr[i], buffer);
450         if(FAILED(hr)) {
451             goto error;
452         }
453     }
454
455     if(FAILED(writer->state)) {
456         hr = writer->state;
457         goto error;
458     }
459
460     writer->funcs->end(writer, shader, buffer);
461
462     if(FAILED(buffer->state)) {
463         hr = buffer->state;
464         goto error;
465     }
466
467     /* Cut off unneeded memory from the result buffer */
468     *result = asm_realloc(buffer->data,
469                          sizeof(DWORD) * buffer->size);
470     if(!*result) {
471         *result = buffer->data;
472     }
473     buffer->data = NULL;
474     hr = S_OK;
475
476 error:
477     if(buffer) {
478         asm_free(buffer->data);
479         asm_free(buffer);
480     }
481     asm_free(writer);
482     return hr;
483 }
484
485 void SlDeleteShader(struct bwriter_shader *shader) {
486     unsigned int i, j;
487
488     TRACE("Deleting shader %p\n", shader);
489
490     for(i = 0; i < shader->num_cf; i++) {
491         asm_free(shader->constF[i]);
492     }
493     asm_free(shader->constF);
494     for(i = 0; i < shader->num_ci; i++) {
495         asm_free(shader->constI[i]);
496     }
497     asm_free(shader->constI);
498     for(i = 0; i < shader->num_cb; i++) {
499         asm_free(shader->constB[i]);
500     }
501     asm_free(shader->constB);
502
503     asm_free(shader->inputs);
504     asm_free(shader->outputs);
505     asm_free(shader->samplers);
506
507     for(i = 0; i < shader->num_instrs; i++) {
508         for(j = 0; j < shader->instr[i]->num_srcs; j++) {
509             asm_free(shader->instr[i]->src[j].rel_reg);
510         }
511         asm_free(shader->instr[i]->src);
512         asm_free(shader->instr[i]);
513     }
514     asm_free(shader->instr);
515
516     asm_free(shader);
517 }