d3dx9: Add sampler dcl instruction support to the shader assembler.
[wine.git] / dlls / d3dx9_36 / bytecodewriter.c
blob82a365537babd068769b9b1580f70ee93ad1f992
1 /*
2 * Direct3D bytecode output functions
4 * Copyright 2008 Stefan Dösinger
5 * Copyright 2009 Matteo Bruni
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.
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.
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
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wine/debug.h"
27 #include "d3dx9_36_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
31 /****************************************************************
32 * General assembler shader construction helper routines follow *
33 ****************************************************************/
34 /* struct instruction *alloc_instr
36 * Allocates a new instruction structure with srcs registers
38 * Parameters:
39 * srcs: Number of source registers to allocate
41 * Returns:
42 * A pointer to the allocated instruction structure
43 * NULL in case of an allocation failure
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;
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;
59 ret->num_srcs = srcs;
61 return ret;
64 /* void add_instruction
66 * Adds a new instruction to the shader's instructions array and grows the instruction array
67 * if needed.
69 * The function does NOT copy the instruction structure. Make sure not to release the
70 * instruction or any of its substructures like registers.
72 * Parameters:
73 * shader: Shader to add the instruction to
74 * instr: Instruction to add to the shader
76 BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr) {
77 struct instruction **new_instructions;
79 if(!shader) return FALSE;
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;
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;
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;
102 shader->instr[shader->num_instrs] = instr;
103 shader->num_instrs++;
104 return TRUE;
107 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) {
108 unsigned int *num;
109 struct declaration **decl;
110 unsigned int i;
112 if(!shader) return FALSE;
114 if(output) {
115 num = &shader->num_outputs;
116 decl = &shader->outputs;
117 } else {
118 num = &shader->num_inputs;
119 decl = &shader->inputs;
122 if(*num == 0) {
123 *decl = asm_alloc(sizeof(**decl));
124 if(!*decl) {
125 ERR("Error allocating declarations array\n");
126 return FALSE;
128 } else {
129 struct declaration *newdecl;
130 for(i = 0; i < *num; i++) {
131 if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
132 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
133 regnum, (*decl)[i].writemask & writemask);
137 newdecl = asm_realloc(*decl,
138 sizeof(**decl) * ((*num) + 1));
139 if(!newdecl) {
140 ERR("Error reallocating declarations array\n");
141 return FALSE;
143 *decl = newdecl;
145 (*decl)[*num].usage = usage;
146 (*decl)[*num].usage_idx = usage_idx;
147 (*decl)[*num].regnum = regnum;
148 (*decl)[*num].writemask = writemask;
149 (*num)++;
151 return TRUE;
154 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD regnum) {
155 unsigned int i;
157 if(!shader) return FALSE;
159 if(shader->num_samplers == 0) {
160 shader->samplers = asm_alloc(sizeof(*shader->samplers));
161 if(!shader->samplers) {
162 ERR("Error allocating samplers array\n");
163 return FALSE;
165 } else {
166 struct samplerdecl *newarray;
168 for(i = 0; i < shader->num_samplers; i++) {
169 if(shader->samplers[i].regnum == regnum) {
170 WARN("Sampler %u already declared\n", regnum);
171 /* This is not an error as far as the assembler is concerned.
172 * Direct3D might refuse to load the compiled shader though
177 newarray = asm_realloc(shader->samplers,
178 sizeof(*shader->samplers) * (shader->num_samplers + 1));
179 if(!newarray) {
180 ERR("Error reallocating samplers array\n");
181 return FALSE;
183 shader->samplers = newarray;
186 shader->samplers[shader->num_samplers].type = samptype;
187 shader->samplers[shader->num_samplers].regnum = regnum;
188 shader->num_samplers++;
189 return TRUE;
193 /* shader bytecode buffer manipulation functions.
194 * allocate_buffer creates a new buffer structure, put_dword adds a new
195 * DWORD to the buffer. In the rare case of a memory allocation failure
196 * when trying to grow the buffer a flag is set in the buffer to mark it
197 * invalid. This avoids return value checking and passing in many places
199 static struct bytecode_buffer *allocate_buffer(void) {
200 struct bytecode_buffer *ret;
202 ret = asm_alloc(sizeof(*ret));
203 if(!ret) return NULL;
205 ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
206 ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
207 if(!ret->data) {
208 asm_free(ret);
209 return NULL;
211 ret->state = S_OK;
212 return ret;
215 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
216 if(FAILED(buffer->state)) return;
218 if(buffer->alloc_size == buffer->size) {
219 DWORD *newarray;
220 buffer->alloc_size *= 2;
221 newarray = asm_realloc(buffer->data,
222 sizeof(DWORD) * buffer->alloc_size);
223 if(!newarray) {
224 ERR("Failed to grow the buffer data memory\n");
225 buffer->state = E_OUTOFMEMORY;
226 return;
228 buffer->data = newarray;
230 buffer->data[buffer->size++] = value;
233 /******************************************************
234 * Implementation of the writer functions starts here *
235 ******************************************************/
236 static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
237 const struct declaration *decls, unsigned int num, DWORD type) {
238 DWORD i;
239 DWORD instr_dcl = D3DSIO_DCL;
240 DWORD token;
242 if(len) {
243 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
246 for(i = 0; i < num; i++) {
247 /* Write the DCL instruction */
248 put_dword(buffer, instr_dcl);
250 /* Write the usage and index */
251 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
252 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
253 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
254 put_dword(buffer, token);
256 /* Write the dest register */
257 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
258 token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
259 token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL;
260 token |= decls[i].regnum & D3DSP_REGNUM_MASK;
261 put_dword(buffer, token);
265 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
266 put_dword(buffer, D3DSIO_END);
269 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
270 struct bytecode_buffer *buffer){
271 unsigned int i;
272 if(instr->has_predicate){
273 This->funcs->srcreg(This, &instr->predicate, buffer);
275 for(i = 0; i < instr->num_srcs; i++){
276 This->funcs->srcreg(This, &instr->src[i], buffer);
280 /* The length of an instruction consists of the destination register (if any),
281 * the number of source registers, the number of address registers used for
282 * indirect addressing, and optionally the predicate register
284 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
285 unsigned int i;
286 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
288 if(dsts){
289 if(instr->dst.rel_reg) ret++;
291 for(i = 0; i < srcs; i++) {
292 if(instr->src[i].rel_reg) ret++;
294 return ret;
297 static void instr_handler(struct bc_writer *This,
298 const struct instruction *instr,
299 struct bytecode_buffer *buffer) {
300 DWORD token = d3d9_opcode(instr->opcode);
301 TRACE("token: %x\n", token);
303 This->funcs->opcode(This, instr, token, buffer);
304 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
305 write_srcregs(This, instr, buffer);
308 static void sm_2_opcode(struct bc_writer *This,
309 const struct instruction *instr,
310 DWORD token, struct bytecode_buffer *buffer) {
311 /* From sm 2 onwards instruction length is encoded in the opcode field */
312 int dsts = instr->has_dst ? 1 : 0;
313 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
314 if(instr->comptype)
315 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
316 if(instr->has_predicate)
317 token |= D3DSHADER_INSTRUCTION_PREDICATED;
318 put_dword(buffer,token);
321 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
322 DWORD i;
323 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
324 DWORD token;
325 const DWORD reg = (1<<31) |
326 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
327 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
328 D3DSP_WRITEMASK_ALL;
330 for(i = 0; i < shader->num_samplers; i++) {
331 /* Write the DCL instruction */
332 put_dword(buffer, instr_dcl);
333 token = (1<<31);
334 /* Already shifted */
335 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
336 put_dword(buffer, token);
337 put_dword(buffer, reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK));
341 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
342 /* Declare the shader type and version */
343 put_dword(buffer, This->version);
345 write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
346 write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT);
347 write_samplers(shader, buffer);
348 return;
351 static void sm_3_srcreg(struct bc_writer *This,
352 const struct shader_reg *reg,
353 struct bytecode_buffer *buffer) {
354 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
355 DWORD d3d9reg;
357 d3d9reg = d3d9_register(reg->type);
358 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
359 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
360 token |= reg->regnum & D3DSP_REGNUM_MASK;
362 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
363 token |= d3d9_srcmod(reg->srcmod);
365 if(reg->rel_reg) {
366 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
367 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
368 This->state = E_INVALIDARG;
369 return;
371 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
372 reg->rel_reg->type == BWRITERSPR_LOOP) &&
373 reg->rel_reg->regnum == 0) {
374 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
375 } else {
376 WARN("Unsupported relative addressing register\n");
377 This->state = E_INVALIDARG;
378 return;
382 put_dword(buffer, token);
384 /* vs_2_0 and newer write the register containing the index explicitly in the
385 * binary code
387 if(token & D3DVS_ADDRMODE_RELATIVE) {
388 sm_3_srcreg(This, reg->rel_reg, buffer);
392 static void sm_3_dstreg(struct bc_writer *This,
393 const struct shader_reg *reg,
394 struct bytecode_buffer *buffer,
395 DWORD shift, DWORD mod) {
396 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
397 DWORD d3d9reg;
399 if(reg->rel_reg) {
400 if(This->version == BWRITERVS_VERSION(3, 0) &&
401 reg->type == BWRITERSPR_OUTPUT) {
402 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
403 } else {
404 WARN("Relative addressing not supported for this shader type or register type\n");
405 This->state = E_INVALIDARG;
406 return;
410 d3d9reg = d3d9_register(reg->type);
411 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
412 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
413 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
415 token |= d3d9_dstmod(mod);
417 token |= d3d9_writemask(reg->writemask);
418 put_dword(buffer, token);
420 /* vs_2_0 and newer write the register containing the index explicitly in the
421 * binary code
423 if(token & D3DVS_ADDRMODE_RELATIVE) {
424 sm_3_srcreg(This, reg->rel_reg, buffer);
428 static const struct instr_handler_table vs_3_handlers[] = {
429 {BWRITERSIO_ADD, instr_handler},
430 {BWRITERSIO_NOP, instr_handler},
431 {BWRITERSIO_MOV, instr_handler},
432 {BWRITERSIO_SUB, instr_handler},
433 {BWRITERSIO_MAD, instr_handler},
434 {BWRITERSIO_MUL, instr_handler},
435 {BWRITERSIO_RCP, instr_handler},
436 {BWRITERSIO_RSQ, instr_handler},
437 {BWRITERSIO_DP3, instr_handler},
438 {BWRITERSIO_DP4, instr_handler},
439 {BWRITERSIO_MIN, instr_handler},
440 {BWRITERSIO_MAX, instr_handler},
441 {BWRITERSIO_SLT, instr_handler},
442 {BWRITERSIO_SGE, instr_handler},
443 {BWRITERSIO_ABS, instr_handler},
444 {BWRITERSIO_EXP, instr_handler},
445 {BWRITERSIO_LOG, instr_handler},
446 {BWRITERSIO_EXPP, instr_handler},
447 {BWRITERSIO_LOGP, instr_handler},
448 {BWRITERSIO_DST, instr_handler},
449 {BWRITERSIO_LRP, instr_handler},
450 {BWRITERSIO_FRC, instr_handler},
451 {BWRITERSIO_CRS, instr_handler},
452 {BWRITERSIO_SGN, instr_handler},
453 {BWRITERSIO_NRM, instr_handler},
454 {BWRITERSIO_SINCOS, instr_handler},
455 {BWRITERSIO_M4x4, instr_handler},
456 {BWRITERSIO_M4x3, instr_handler},
457 {BWRITERSIO_M3x4, instr_handler},
458 {BWRITERSIO_M3x3, instr_handler},
459 {BWRITERSIO_M3x2, instr_handler},
460 {BWRITERSIO_LIT, instr_handler},
461 {BWRITERSIO_POW, instr_handler},
462 {BWRITERSIO_MOVA, instr_handler},
464 {BWRITERSIO_CALL, instr_handler},
465 {BWRITERSIO_CALLNZ, instr_handler},
466 {BWRITERSIO_REP, instr_handler},
467 {BWRITERSIO_ENDREP, instr_handler},
468 {BWRITERSIO_IF, instr_handler},
469 {BWRITERSIO_LABEL, instr_handler},
470 {BWRITERSIO_IFC, instr_handler},
471 {BWRITERSIO_ELSE, instr_handler},
472 {BWRITERSIO_ENDIF, instr_handler},
473 {BWRITERSIO_BREAK, instr_handler},
474 {BWRITERSIO_BREAKC, instr_handler},
475 {BWRITERSIO_LOOP, instr_handler},
476 {BWRITERSIO_RET, instr_handler},
477 {BWRITERSIO_ENDLOOP, instr_handler},
479 {BWRITERSIO_SETP, instr_handler},
480 {BWRITERSIO_BREAKP, instr_handler},
481 {BWRITERSIO_TEXLDL, instr_handler},
483 {BWRITERSIO_END, NULL},
486 static const struct bytecode_backend vs_3_backend = {
487 sm_3_header,
488 end,
489 sm_3_srcreg,
490 sm_3_dstreg,
491 sm_2_opcode,
492 vs_3_handlers
495 static void init_vs30_dx9_writer(struct bc_writer *writer) {
496 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
497 writer->funcs = &vs_3_backend;
500 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
501 struct bc_writer *ret = asm_alloc(sizeof(*ret));
503 if(!ret) {
504 WARN("Failed to allocate a bytecode writer instance\n");
505 return NULL;
508 switch(version) {
509 case BWRITERVS_VERSION(1, 0):
510 if(dxversion != 9) {
511 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
512 goto fail;
514 /* TODO: Set the appropriate writer backend */
515 break;
516 case BWRITERVS_VERSION(1, 1):
517 if(dxversion != 9) {
518 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
519 goto fail;
521 /* TODO: Set the appropriate writer backend */
522 break;
523 case BWRITERVS_VERSION(2, 0):
524 if(dxversion != 9) {
525 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
526 goto fail;
528 /* TODO: Set the appropriate writer backend */
529 break;
530 case BWRITERVS_VERSION(2, 1):
531 if(dxversion != 9) {
532 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
533 goto fail;
535 /* TODO: Set the appropriate writer backend */
536 break;
537 case BWRITERVS_VERSION(3, 0):
538 if(dxversion != 9) {
539 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
540 goto fail;
542 init_vs30_dx9_writer(ret);
543 break;
545 case BWRITERPS_VERSION(1, 0):
546 if(dxversion != 9) {
547 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
548 goto fail;
550 /* TODO: Set the appropriate writer backend */
551 break;
552 case BWRITERPS_VERSION(1, 1):
553 if(dxversion != 9) {
554 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
555 goto fail;
557 /* TODO: Set the appropriate writer backend */
558 break;
559 case BWRITERPS_VERSION(1, 2):
560 if(dxversion != 9) {
561 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
562 goto fail;
564 /* TODO: Set the appropriate writer backend */
565 break;
566 case BWRITERPS_VERSION(1, 3):
567 if(dxversion != 9) {
568 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
569 goto fail;
571 /* TODO: Set the appropriate writer backend */
572 break;
573 case BWRITERPS_VERSION(1, 4):
574 if(dxversion != 9) {
575 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
576 goto fail;
578 /* TODO: Set the appropriate writer backend */
579 break;
581 case BWRITERPS_VERSION(2, 0):
582 if(dxversion != 9) {
583 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
584 goto fail;
586 /* TODO: Set the appropriate writer backend */
587 break;
589 case BWRITERPS_VERSION(2, 1):
590 if(dxversion != 9) {
591 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
592 goto fail;
594 /* TODO: Set the appropriate writer backend */
595 break;
597 case BWRITERPS_VERSION(3, 0):
598 if(dxversion != 9) {
599 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
600 goto fail;
602 /* TODO: Set the appropriate writer backend */
603 break;
605 default:
606 WARN("Unexpected shader version requested: %08x\n", version);
607 goto fail;
609 ret->version = version;
610 return ret;
612 fail:
613 asm_free(ret);
614 return NULL;
617 static HRESULT call_instr_handler(struct bc_writer *writer,
618 const struct instruction *instr,
619 struct bytecode_buffer *buffer) {
620 DWORD i=0;
622 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
623 if(instr->opcode == writer->funcs->instructions[i].opcode) {
624 if(!writer->funcs->instructions[i].func) {
625 WARN("Opcode %u not supported by this profile\n", instr->opcode);
626 return E_INVALIDARG;
628 writer->funcs->instructions[i].func(writer, instr, buffer);
629 return S_OK;
631 i++;
634 FIXME("Unhandled instruction %u\n", instr->opcode);
635 return E_INVALIDARG;
638 /* SlWriteBytecode (wineshader.@)
640 * Writes shader version specific bytecode from the shader passed in.
641 * The returned bytecode can be passed to the Direct3D runtime like
642 * IDirect3DDevice9::Create*Shader.
644 * Parameters:
645 * shader: Shader to translate into bytecode
646 * version: Shader version to generate(d3d version token)
647 * dxversion: DirectX version the code targets
648 * result: the resulting shader bytecode
650 * Return values:
651 * S_OK on success
653 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
654 struct bc_writer *writer;
655 struct bytecode_buffer *buffer = NULL;
656 HRESULT hr;
657 unsigned int i;
659 if(!shader){
660 ERR("NULL shader structure, aborting\n");
661 return E_FAIL;
663 writer = create_writer(shader->version, dxversion);
664 *result = NULL;
666 if(!writer) {
667 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
668 WARN("or out of memory\n");
669 hr = E_FAIL;
670 goto error;
673 buffer = allocate_buffer();
674 if(!buffer) {
675 WARN("Failed to allocate a buffer for the shader bytecode\n");
676 hr = E_FAIL;
677 goto error;
680 writer->funcs->header(writer, shader, buffer);
681 if(FAILED(writer->state)) {
682 hr = writer->state;
683 goto error;
686 for(i = 0; i < shader->num_instrs; i++) {
687 hr = call_instr_handler(writer, shader->instr[i], buffer);
688 if(FAILED(hr)) {
689 goto error;
693 if(FAILED(writer->state)) {
694 hr = writer->state;
695 goto error;
698 writer->funcs->end(writer, shader, buffer);
700 if(FAILED(buffer->state)) {
701 hr = buffer->state;
702 goto error;
705 /* Cut off unneeded memory from the result buffer */
706 *result = asm_realloc(buffer->data,
707 sizeof(DWORD) * buffer->size);
708 if(!*result) {
709 *result = buffer->data;
711 buffer->data = NULL;
712 hr = S_OK;
714 error:
715 if(buffer) {
716 asm_free(buffer->data);
717 asm_free(buffer);
719 asm_free(writer);
720 return hr;
723 void SlDeleteShader(struct bwriter_shader *shader) {
724 unsigned int i, j;
726 TRACE("Deleting shader %p\n", shader);
728 for(i = 0; i < shader->num_cf; i++) {
729 asm_free(shader->constF[i]);
731 asm_free(shader->constF);
732 for(i = 0; i < shader->num_ci; i++) {
733 asm_free(shader->constI[i]);
735 asm_free(shader->constI);
736 for(i = 0; i < shader->num_cb; i++) {
737 asm_free(shader->constB[i]);
739 asm_free(shader->constB);
741 asm_free(shader->inputs);
742 asm_free(shader->outputs);
743 asm_free(shader->samplers);
745 for(i = 0; i < shader->num_instrs; i++) {
746 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
747 asm_free(shader->instr[i]->src[j].rel_reg);
749 asm_free(shader->instr[i]->src);
750 asm_free(shader->instr[i]);
752 asm_free(shader->instr);
754 asm_free(shader);