d3dcompiler_37: Stub dll.
[wine/multimedia.git] / dlls / d3dx9_36 / bytecodewriter.c
blob07f96e74e794399db8cfaec9705545e5751e5b0c
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 add_constF(struct bwriter_shader *shader, DWORD reg, float x, float y, float z, float w) {
108 struct constant *newconst;
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;
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;
127 newconst = asm_alloc(sizeof(*newconst));
128 if(!newconst) {
129 ERR("Failed to allocate a new constant\n");
130 return FALSE;
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;
139 shader->num_cf++;
140 return TRUE;
143 BOOL add_constI(struct bwriter_shader *shader, DWORD reg, INT x, INT y, INT z, INT w) {
144 struct constant *newconst;
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;
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;
163 newconst = asm_alloc(sizeof(*newconst));
164 if(!newconst) {
165 ERR("Failed to allocate a new constant\n");
166 return FALSE;
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;
175 shader->num_ci++;
176 return TRUE;
179 BOOL add_constB(struct bwriter_shader *shader, DWORD reg, BOOL x) {
180 struct constant *newconst;
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;
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;
199 newconst = asm_alloc(sizeof(*newconst));
200 if(!newconst) {
201 ERR("Failed to allocate a new constant\n");
202 return FALSE;
204 newconst->regnum = reg;
205 newconst->value[0].b = x;
206 shader->constB[shader->num_cb] = newconst;
208 shader->num_cb++;
209 return TRUE;
212 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage,
213 DWORD usage_idx, DWORD mod, BOOL output,
214 DWORD regnum, DWORD writemask, BOOL builtin) {
215 unsigned int *num;
216 struct declaration **decl;
217 unsigned int i;
219 if(!shader) return FALSE;
221 if(output) {
222 num = &shader->num_outputs;
223 decl = &shader->outputs;
224 } else {
225 num = &shader->num_inputs;
226 decl = &shader->inputs;
229 if(*num == 0) {
230 *decl = asm_alloc(sizeof(**decl));
231 if(!*decl) {
232 ERR("Error allocating declarations array\n");
233 return FALSE;
235 } else {
236 struct declaration *newdecl;
237 for(i = 0; i < *num; i++) {
238 if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
239 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
240 regnum, (*decl)[i].writemask & writemask);
244 newdecl = asm_realloc(*decl,
245 sizeof(**decl) * ((*num) + 1));
246 if(!newdecl) {
247 ERR("Error reallocating declarations array\n");
248 return FALSE;
250 *decl = newdecl;
252 (*decl)[*num].usage = usage;
253 (*decl)[*num].usage_idx = usage_idx;
254 (*decl)[*num].regnum = regnum;
255 (*decl)[*num].mod = mod;
256 (*decl)[*num].writemask = writemask;
257 (*decl)[*num].builtin = builtin;
258 (*num)++;
260 return TRUE;
263 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD mod, DWORD regnum) {
264 unsigned int i;
266 if(!shader) return FALSE;
268 if(shader->num_samplers == 0) {
269 shader->samplers = asm_alloc(sizeof(*shader->samplers));
270 if(!shader->samplers) {
271 ERR("Error allocating samplers array\n");
272 return FALSE;
274 } else {
275 struct samplerdecl *newarray;
277 for(i = 0; i < shader->num_samplers; i++) {
278 if(shader->samplers[i].regnum == regnum) {
279 WARN("Sampler %u already declared\n", regnum);
280 /* This is not an error as far as the assembler is concerned.
281 * Direct3D might refuse to load the compiled shader though
286 newarray = asm_realloc(shader->samplers,
287 sizeof(*shader->samplers) * (shader->num_samplers + 1));
288 if(!newarray) {
289 ERR("Error reallocating samplers array\n");
290 return FALSE;
292 shader->samplers = newarray;
295 shader->samplers[shader->num_samplers].type = samptype;
296 shader->samplers[shader->num_samplers].mod = mod;
297 shader->samplers[shader->num_samplers].regnum = regnum;
298 shader->num_samplers++;
299 return TRUE;
303 /* shader bytecode buffer manipulation functions.
304 * allocate_buffer creates a new buffer structure, put_dword adds a new
305 * DWORD to the buffer. In the rare case of a memory allocation failure
306 * when trying to grow the buffer a flag is set in the buffer to mark it
307 * invalid. This avoids return value checking and passing in many places
309 static struct bytecode_buffer *allocate_buffer(void) {
310 struct bytecode_buffer *ret;
312 ret = asm_alloc(sizeof(*ret));
313 if(!ret) return NULL;
315 ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
316 ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
317 if(!ret->data) {
318 asm_free(ret);
319 return NULL;
321 ret->state = S_OK;
322 return ret;
325 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
326 if(FAILED(buffer->state)) return;
328 if(buffer->alloc_size == buffer->size) {
329 DWORD *newarray;
330 buffer->alloc_size *= 2;
331 newarray = asm_realloc(buffer->data,
332 sizeof(DWORD) * buffer->alloc_size);
333 if(!newarray) {
334 ERR("Failed to grow the buffer data memory\n");
335 buffer->state = E_OUTOFMEMORY;
336 return;
338 buffer->data = newarray;
340 buffer->data[buffer->size++] = value;
343 /******************************************************
344 * Implementation of the writer functions starts here *
345 ******************************************************/
346 static void write_declarations(struct bc_writer *This,
347 struct bytecode_buffer *buffer, BOOL len,
348 const struct declaration *decls, unsigned int num, DWORD type) {
349 DWORD i;
350 DWORD instr_dcl = D3DSIO_DCL;
351 DWORD token;
352 struct shader_reg reg;
354 ZeroMemory(&reg, sizeof(reg));
356 if(len) {
357 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
360 for(i = 0; i < num; i++) {
361 if(decls[i].builtin) continue;
363 /* Write the DCL instruction */
364 put_dword(buffer, instr_dcl);
366 /* Write the usage and index */
367 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
368 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
369 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
370 put_dword(buffer, token);
372 /* Write the dest register */
373 reg.type = type;
374 reg.regnum = decls[i].regnum;
375 reg.writemask = decls[i].writemask;
376 This->funcs->dstreg(This, &reg, buffer, 0, decls[i].mod);
380 static void write_const(struct constant **consts, int num, DWORD opcode, DWORD reg_type, struct bytecode_buffer *buffer, BOOL len) {
381 DWORD i;
382 DWORD instr_def = opcode;
383 const DWORD reg = (1<<31) |
384 ((reg_type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
385 ((reg_type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
386 D3DSP_WRITEMASK_ALL;
388 if(len) {
389 if(opcode == D3DSIO_DEFB)
390 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
391 else
392 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
395 for(i = 0; i < num; i++) {
396 /* Write the DEF instruction */
397 put_dword(buffer, instr_def);
399 put_dword(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
400 put_dword(buffer, consts[i]->value[0].d);
401 if(opcode != D3DSIO_DEFB) {
402 put_dword(buffer, consts[i]->value[1].d);
403 put_dword(buffer, consts[i]->value[2].d);
404 put_dword(buffer, consts[i]->value[3].d);
409 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
410 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
413 /* This function looks for VS 1/2 registers mapping to VS 3 output registers */
414 static HRESULT vs_find_builtin_varyings(struct bc_writer *This, const struct bwriter_shader *shader) {
415 DWORD i;
416 DWORD usage, usage_idx, writemask, regnum;
418 for(i = 0; i < shader->num_outputs; i++) {
419 if(!shader->outputs[i].builtin) continue;
421 usage = shader->outputs[i].usage;
422 usage_idx = shader->outputs[i].usage_idx;
423 writemask = shader->outputs[i].writemask;
424 regnum = shader->outputs[i].regnum;
426 switch(usage) {
427 case BWRITERDECLUSAGE_POSITION:
428 case BWRITERDECLUSAGE_POSITIONT:
429 if(usage_idx > 0) {
430 WARN("dcl_position%u not supported in sm 1/2 shaders\n", usage_idx);
431 return E_INVALIDARG;
433 TRACE("o%u is oPos\n", regnum);
434 This->oPos_regnum = regnum;
435 break;
437 case BWRITERDECLUSAGE_COLOR:
438 if(usage_idx > 1) {
439 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
440 return E_INVALIDARG;
442 if(writemask != BWRITERSP_WRITEMASK_ALL) {
443 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
444 return E_INVALIDARG;
446 TRACE("o%u is oD%u\n", regnum, usage_idx);
447 This->oD_regnum[usage_idx] = regnum;
448 break;
450 case BWRITERDECLUSAGE_TEXCOORD:
451 if(usage_idx >= 8) {
452 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
453 return E_INVALIDARG;
455 if(writemask != (BWRITERSP_WRITEMASK_0) &&
456 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
457 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
458 writemask != (BWRITERSP_WRITEMASK_ALL)) {
459 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
460 return E_INVALIDARG;
462 TRACE("o%u is oT%u\n", regnum, usage_idx);
463 This->oT_regnum[usage_idx] = regnum;
464 break;
466 case BWRITERDECLUSAGE_PSIZE:
467 if(usage_idx > 0) {
468 WARN("dcl_psize%u not supported in sm 1/2 shaders\n", usage_idx);
469 return E_INVALIDARG;
471 TRACE("o%u writemask 0x%08x is oPts\n", regnum, writemask);
472 This->oPts_regnum = regnum;
473 This->oPts_mask = writemask;
474 break;
476 case BWRITERDECLUSAGE_FOG:
477 if(usage_idx > 0) {
478 WARN("dcl_fog%u not supported in sm 1 shaders\n", usage_idx);
479 return E_INVALIDARG;
481 if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
482 writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
483 WARN("Unsupported fog writemask\n");
484 return E_INVALIDARG;
486 TRACE("o%u writemask 0x%08x is oFog\n", regnum, writemask);
487 This->oFog_regnum = regnum;
488 This->oFog_mask = writemask;
489 break;
491 default:
492 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
493 return E_INVALIDARG;
497 return S_OK;
500 static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
501 HRESULT hr;
503 if(shader->num_ci || shader->num_cb) {
504 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
505 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
506 This->state = E_INVALIDARG;
507 return;
510 hr = vs_find_builtin_varyings(This, shader);
511 if(FAILED(hr)) {
512 This->state = hr;
513 return;
516 /* Declare the shader type and version */
517 put_dword(buffer, This->version);
519 write_declarations(This, buffer, FALSE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
520 write_constF(shader, buffer, FALSE);
521 return;
524 static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
525 const struct bwriter_shader *shader,
526 DWORD texcoords) {
527 DWORD i;
528 DWORD usage, usage_idx, writemask, regnum;
530 This->v_regnum[0] = -1; This->v_regnum[1] = -1;
531 for(i = 0; i < 8; i++) This->t_regnum[i] = -1;
533 for(i = 0; i < shader->num_inputs; i++) {
534 if(!shader->inputs[i].builtin) continue;
536 usage = shader->inputs[i].usage;
537 usage_idx = shader->inputs[i].usage_idx;
538 writemask = shader->inputs[i].writemask;
539 regnum = shader->inputs[i].regnum;
541 switch(usage) {
542 case BWRITERDECLUSAGE_COLOR:
543 if(usage_idx > 1) {
544 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
545 return E_INVALIDARG;
547 if(writemask != BWRITERSP_WRITEMASK_ALL) {
548 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
549 return E_INVALIDARG;
551 TRACE("v%u is v%u\n", regnum, usage_idx);
552 This->v_regnum[usage_idx] = regnum;
553 break;
555 case BWRITERDECLUSAGE_TEXCOORD:
556 if(usage_idx > texcoords) {
557 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
558 return E_INVALIDARG;
560 if(writemask != (BWRITERSP_WRITEMASK_0) &&
561 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
562 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
563 writemask != (BWRITERSP_WRITEMASK_ALL)) {
564 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
565 } else {
566 writemask = BWRITERSP_WRITEMASK_ALL;
568 TRACE("v%u is t%u\n", regnum, usage_idx);
569 This->t_regnum[usage_idx] = regnum;
570 break;
572 default:
573 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
574 return E_INVALIDARG;
578 return S_OK;
581 static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
582 HRESULT hr;
584 /* First check the constants and varyings, and complain if unsupported things are used */
585 if(shader->num_ci || shader->num_cb) {
586 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
587 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
588 This->state = E_INVALIDARG;
589 return;
592 hr = find_ps_builtin_semantics(This, shader, 4);
593 if(FAILED(hr)) {
594 This->state = hr;
595 return;
598 /* Declare the shader type and version */
599 put_dword(buffer, This->version);
600 write_constF(shader, buffer, TRUE);
603 static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
604 HRESULT hr;
606 /* First check the constants and varyings, and complain if unsupported things are used */
607 if(shader->num_ci || shader->num_cb) {
608 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
609 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
610 This->state = E_INVALIDARG;
611 return;
613 hr = find_ps_builtin_semantics(This, shader, 6);
614 if(FAILED(hr)) {
615 This->state = hr;
616 return;
619 /* Declare the shader type and version */
620 put_dword(buffer, This->version);
621 write_constF(shader, buffer, TRUE);
624 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
625 put_dword(buffer, D3DSIO_END);
628 static DWORD map_vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
629 DWORD token = 0;
630 DWORD i;
632 *has_components = TRUE;
633 if(regnum == This->oPos_regnum) {
634 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
635 token |= D3DSRO_POSITION & D3DSP_REGNUM_MASK; /* No shift */
636 return token;
638 if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
639 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
640 token |= D3DSRO_FOG & D3DSP_REGNUM_MASK; /* No shift */
641 token |= D3DSP_WRITEMASK_ALL;
642 *has_components = FALSE;
643 return token;
645 if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
646 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
647 token |= D3DSRO_POINT_SIZE & D3DSP_REGNUM_MASK; /* No shift */
648 token |= D3DSP_WRITEMASK_ALL;
649 *has_components = FALSE;
650 return token;
652 for(i = 0; i < 2; i++) {
653 if(regnum == This->oD_regnum[i]) {
654 token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
655 token |= i & D3DSP_REGNUM_MASK; /* No shift */
656 return token;
659 for(i = 0; i < 8; i++) {
660 if(regnum == This->oT_regnum[i]) {
661 token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
662 token |= i & D3DSP_REGNUM_MASK; /* No shift */
663 return token;
667 /* The varying must be undeclared - if an unsupported varying was declared,
668 * the vs_find_builtin_varyings function would have caught it and this code
669 * would not run */
670 WARN("Undeclared varying %u\n", regnum);
671 This->state = E_INVALIDARG;
672 return -1;
675 static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
676 struct bytecode_buffer *buffer,
677 DWORD shift, DWORD mod) {
678 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
679 DWORD has_wmask;
681 if(reg->rel_reg) {
682 WARN("Relative addressing not supported for destination registers\n");
683 This->state = E_INVALIDARG;
684 return;
687 switch(reg->type) {
688 case BWRITERSPR_OUTPUT:
689 token |= map_vs_output(This, reg->regnum, reg->writemask, &has_wmask);
690 break;
692 case BWRITERSPR_RASTOUT:
693 case BWRITERSPR_ATTROUT:
694 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
695 * but are unexpected. If we hit this path it might be due to an error.
697 FIXME("Unexpected register type %u\n", reg->type);
698 /* drop through */
699 case BWRITERSPR_INPUT:
700 case BWRITERSPR_TEMP:
701 case BWRITERSPR_CONST:
702 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
703 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
704 has_wmask = TRUE;
705 break;
707 case BWRITERSPR_ADDR:
708 if(reg->regnum != 0) {
709 WARN("Only a0 exists\n");
710 This->state = E_INVALIDARG;
711 return;
713 token |= (D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
714 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
715 has_wmask = TRUE;
716 break;
718 case BWRITERSPR_PREDICATE:
719 if(This->version != BWRITERVS_VERSION(2, 1)){
720 WARN("Predicate register is allowed only in vs_2_x\n");
721 This->state = E_INVALIDARG;
722 return;
724 if(reg->regnum != 0) {
725 WARN("Only predicate register p0 exists\n");
726 This->state = E_INVALIDARG;
727 return;
729 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
730 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
731 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
732 has_wmask = TRUE;
733 break;
735 default:
736 WARN("Invalid register type for 1.x-2.x vertex shader\n");
737 This->state = E_INVALIDARG;
738 return;
741 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
742 * into the bytecode and since the compiler doesn't do such checks write them
743 * (the checks are done by the undocumented shader validator)
745 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
746 token |= d3d9_dstmod(mod);
748 if(has_wmask) {
749 token |= d3d9_writemask(reg->writemask);
751 put_dword(buffer, token);
754 static void vs_1_x_srcreg(struct bc_writer *This, const struct shader_reg *reg,
755 struct bytecode_buffer *buffer) {
756 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
757 DWORD has_swizzle;
758 DWORD component;
760 switch(reg->type) {
761 case BWRITERSPR_OUTPUT:
762 /* Map the swizzle to a writemask, the format expected
763 by map_vs_output
765 switch(reg->swizzle) {
766 case BWRITERVS_SWIZZLE_X:
767 component = BWRITERSP_WRITEMASK_0;
768 break;
769 case BWRITERVS_SWIZZLE_Y:
770 component = BWRITERSP_WRITEMASK_1;
771 break;
772 case BWRITERVS_SWIZZLE_Z:
773 component = BWRITERSP_WRITEMASK_2;
774 break;
775 case BWRITERVS_SWIZZLE_W:
776 component = BWRITERSP_WRITEMASK_3;
777 break;
778 default:
779 component = 0;
781 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
782 break;
784 case BWRITERSPR_RASTOUT:
785 case BWRITERSPR_ATTROUT:
786 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
787 * but are unexpected. If we hit this path it might be due to an error.
789 FIXME("Unexpected register type %u\n", reg->type);
790 /* drop through */
791 case BWRITERSPR_INPUT:
792 case BWRITERSPR_TEMP:
793 case BWRITERSPR_CONST:
794 case BWRITERSPR_ADDR:
795 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
796 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
797 if(reg->rel_reg) {
798 if(reg->rel_reg->type != BWRITERSPR_ADDR ||
799 reg->rel_reg->regnum != 0 ||
800 reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X) {
801 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
802 This->state = E_INVALIDARG;
803 return;
805 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
807 break;
809 default:
810 WARN("Invalid register type for 1.x vshader\n");
811 This->state = E_INVALIDARG;
812 return;
815 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
817 token |= d3d9_srcmod(reg->srcmod);
818 put_dword(buffer, token);
821 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
822 struct bytecode_buffer *buffer){
823 unsigned int i;
824 if(instr->has_predicate){
825 This->funcs->srcreg(This, &instr->predicate, buffer);
827 for(i = 0; i < instr->num_srcs; i++){
828 This->funcs->srcreg(This, &instr->src[i], buffer);
832 static DWORD map_ps13_temp(struct bc_writer *This, const struct shader_reg *reg) {
833 DWORD token = 0;
834 if(reg->regnum == T0_REG) {
835 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
836 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
837 } else if(reg->regnum == T1_REG) {
838 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
839 token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
840 } else if(reg->regnum == T2_REG) {
841 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
842 token |= 2 & D3DSP_REGNUM_MASK; /* No shift */
843 } else if(reg->regnum == T3_REG) {
844 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
845 token |= 3 & D3DSP_REGNUM_MASK; /* No shift */
846 } else {
847 token |= (D3DSPR_TEMP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
848 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
850 return token;
853 static DWORD map_ps_input(struct bc_writer *This,
854 const struct shader_reg *reg) {
855 DWORD i, token = 0;
856 /* Map color interpolators */
857 for(i = 0; i < 2; i++) {
858 if(reg->regnum == This->v_regnum[i]) {
859 token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
860 token |= i & D3DSP_REGNUM_MASK; /* No shift */
861 return token;
864 for(i = 0; i < 8; i++) {
865 if(reg->regnum == This->t_regnum[i]) {
866 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
867 token |= i & D3DSP_REGNUM_MASK; /* No shift */
868 return token;
872 WARN("Invalid ps 1/2 varying\n");
873 This->state = E_INVALIDARG;
874 return token;
877 static void ps_1_0123_srcreg(struct bc_writer *This, const struct shader_reg *reg,
878 struct bytecode_buffer *buffer) {
879 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
880 if(reg->rel_reg) {
881 WARN("Relative addressing not supported in <= ps_3_0\n");
882 This->state = E_INVALIDARG;
883 return;
886 switch(reg->type) {
887 case BWRITERSPR_INPUT:
888 token |= map_ps_input(This, reg);
889 break;
891 /* Take care about the texture temporaries. There's a problem: They aren't
892 * declared anywhere, so we can only hardcode the values that are used
893 * to map ps_1_3 shaders to the common shader structure
895 case BWRITERSPR_TEMP:
896 token |= map_ps13_temp(This, reg);
897 break;
899 case BWRITERSPR_CONST: /* Can be mapped 1:1 */
900 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
901 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
902 break;
904 default:
905 WARN("Invalid register type for <= ps_1_3 shader\n");
906 This->state = E_INVALIDARG;
907 return;
910 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
912 if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW ||
913 reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
914 reg->srcmod == BWRITERSPSM_NOT) {
915 WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
916 This->state = E_INVALIDARG;
917 return;
919 token |= d3d9_srcmod(reg->srcmod);
920 put_dword(buffer, token);
923 static void ps_1_0123_dstreg(struct bc_writer *This, const struct shader_reg *reg,
924 struct bytecode_buffer *buffer,
925 DWORD shift, DWORD mod) {
926 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
928 if(reg->rel_reg) {
929 WARN("Relative addressing not supported for destination registers\n");
930 This->state = E_INVALIDARG;
931 return;
934 switch(reg->type) {
935 case BWRITERSPR_TEMP:
936 token |= map_ps13_temp(This, reg);
937 break;
939 /* texkill uses the input register as a destination parameter */
940 case BWRITERSPR_INPUT:
941 token |= map_ps_input(This, reg);
942 break;
944 default:
945 WARN("Invalid dest register type for 1.x pshader\n");
946 This->state = E_INVALIDARG;
947 return;
950 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
951 token |= d3d9_dstmod(mod);
953 token |= d3d9_writemask(reg->writemask);
954 put_dword(buffer, token);
957 /* The length of an instruction consists of the destination register (if any),
958 * the number of source registers, the number of address registers used for
959 * indirect addressing, and optionally the predicate register
961 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
962 unsigned int i;
963 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
965 if(dsts){
966 if(instr->dst.rel_reg) ret++;
968 for(i = 0; i < srcs; i++) {
969 if(instr->src[i].rel_reg) ret++;
971 return ret;
974 static void sm_1_x_opcode(struct bc_writer *This,
975 const struct instruction *instr,
976 DWORD token, struct bytecode_buffer *buffer) {
977 /* In sm_1_x instruction length isn't encoded */
978 if(instr->coissue){
979 token |= D3DSI_COISSUE;
981 put_dword(buffer, token);
984 static void instr_handler(struct bc_writer *This,
985 const struct instruction *instr,
986 struct bytecode_buffer *buffer) {
987 DWORD token = d3d9_opcode(instr->opcode);
989 This->funcs->opcode(This, instr, token, buffer);
990 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
991 write_srcregs(This, instr, buffer);
994 static const struct instr_handler_table vs_1_x_handlers[] = {
995 {BWRITERSIO_ADD, instr_handler},
996 {BWRITERSIO_NOP, instr_handler},
997 {BWRITERSIO_MOV, instr_handler},
998 {BWRITERSIO_SUB, instr_handler},
999 {BWRITERSIO_MAD, instr_handler},
1000 {BWRITERSIO_MUL, instr_handler},
1001 {BWRITERSIO_RCP, instr_handler},
1002 {BWRITERSIO_RSQ, instr_handler},
1003 {BWRITERSIO_DP3, instr_handler},
1004 {BWRITERSIO_DP4, instr_handler},
1005 {BWRITERSIO_MIN, instr_handler},
1006 {BWRITERSIO_MAX, instr_handler},
1007 {BWRITERSIO_SLT, instr_handler},
1008 {BWRITERSIO_SGE, instr_handler},
1009 {BWRITERSIO_EXP, instr_handler},
1010 {BWRITERSIO_LOG, instr_handler},
1011 {BWRITERSIO_EXPP, instr_handler},
1012 {BWRITERSIO_LOGP, instr_handler},
1013 {BWRITERSIO_DST, instr_handler},
1014 {BWRITERSIO_FRC, instr_handler},
1015 {BWRITERSIO_M4x4, instr_handler},
1016 {BWRITERSIO_M4x3, instr_handler},
1017 {BWRITERSIO_M3x4, instr_handler},
1018 {BWRITERSIO_M3x3, instr_handler},
1019 {BWRITERSIO_M3x2, instr_handler},
1020 {BWRITERSIO_LIT, instr_handler},
1022 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
1023 the end of the list */
1026 static const struct bytecode_backend vs_1_x_backend = {
1027 vs_1_x_header,
1028 end,
1029 vs_1_x_srcreg,
1030 vs_12_dstreg,
1031 sm_1_x_opcode,
1032 vs_1_x_handlers
1035 static void instr_ps_1_0123_texld(struct bc_writer *This,
1036 const struct instruction *instr,
1037 struct bytecode_buffer *buffer) {
1038 DWORD idx, srcidx;
1039 struct shader_reg reg;
1040 DWORD swizzlemask;
1042 if(instr->src[1].type != BWRITERSPR_SAMPLER ||
1043 instr->src[1].regnum > 3) {
1044 WARN("Unsupported sampler type %u regnum %u\n",
1045 instr->src[1].type, instr->src[1].regnum);
1046 This->state = E_INVALIDARG;
1047 return;
1048 } else if(instr->dst.type != BWRITERSPR_TEMP) {
1049 WARN("Can only sample into a temp register\n");
1050 This->state = E_INVALIDARG;
1051 return;
1054 idx = instr->src[1].regnum;
1055 if((idx == 0 && instr->dst.regnum != T0_REG) ||
1056 (idx == 1 && instr->dst.regnum != T1_REG) ||
1057 (idx == 2 && instr->dst.regnum != T2_REG) ||
1058 (idx == 3 && instr->dst.regnum != T3_REG)) {
1059 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n",
1060 idx, instr->dst.regnum);
1061 This->state = E_INVALIDARG;
1062 return;
1064 if(instr->src[0].type == BWRITERSPR_INPUT) {
1065 /* A simple non-dependent read tex instruction */
1066 if(instr->src[0].regnum != This->t_regnum[idx]) {
1067 WARN("Cannot sample from s%u with texture address data from interpolator %u\n",
1068 idx, instr->src[0].regnum);
1069 This->state = E_INVALIDARG;
1070 return;
1072 This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1074 /* map the temp dstreg to the ps_1_3 texture temporary register */
1075 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1076 } else if(instr->src[0].type == BWRITERSPR_TEMP) {
1077 if(instr->src[0].regnum == T0_REG) {
1078 srcidx = 0;
1079 } else if(instr->src[0].regnum == T1_REG) {
1080 srcidx = 1;
1081 } else if(instr->src[0].regnum == T2_REG) {
1082 srcidx = 2;
1083 } else if(instr->src[0].regnum == T3_REG) {
1084 srcidx = 3;
1085 } else {
1086 WARN("Invalid address data source register r%u\n", instr->src[0].regnum);
1089 swizzlemask = (3 << BWRITERVS_SWIZZLE_SHIFT) |
1090 (3 << (BWRITERVS_SWIZZLE_SHIFT + 2)) |
1091 (3 << (BWRITERVS_SWIZZLE_SHIFT + 4));
1092 if((instr->src[0].swizzle & swizzlemask) == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z)) {
1093 TRACE("writing texreg2rgb\n");
1094 This->funcs->opcode(This, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
1095 } else if(instr->src[0].swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)) {
1096 TRACE("writing texreg2ar\n");
1097 This->funcs->opcode(This, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
1098 } else if(instr->src[0].swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)) {
1099 TRACE("writing texreg2gb\n");
1100 This->funcs->opcode(This, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
1101 } else {
1102 WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].swizzle);
1103 This->state = E_INVALIDARG;
1104 return;
1107 /* Dst and src reg can be mapped normally. Both registers are temporary registers in the
1108 * source shader and have to be mapped to the temporary form of the texture registers. However,
1109 * the src reg doesn't have a swizzle
1111 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1112 reg = instr->src[0];
1113 reg.swizzle = BWRITERVS_NOSWIZZLE;
1114 This->funcs->srcreg(This, &reg, buffer);
1115 } else {
1116 WARN("Invalid address data source register\n");
1117 This->state = E_INVALIDARG;
1118 return;
1122 static void instr_ps_1_0123_mov(struct bc_writer *This,
1123 const struct instruction *instr,
1124 struct bytecode_buffer *buffer) {
1125 DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1127 if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
1128 if((instr->dst.regnum == T0_REG && instr->src[0].regnum == This->t_regnum[0]) ||
1129 (instr->dst.regnum == T1_REG && instr->src[0].regnum == This->t_regnum[1]) ||
1130 (instr->dst.regnum == T2_REG && instr->src[0].regnum == This->t_regnum[2]) ||
1131 (instr->dst.regnum == T3_REG && instr->src[0].regnum == This->t_regnum[3])) {
1132 if(instr->dstmod & BWRITERSPDM_SATURATE) {
1133 This->funcs->opcode(This, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
1134 /* Remove the SATURATE flag, it's implicit to the instruction */
1135 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
1136 return;
1137 } else {
1138 WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
1139 This->state = E_INVALIDARG;
1140 return;
1142 } else if(instr->src[0].regnum == This->v_regnum[0] ||
1143 instr->src[0].regnum == This->v_regnum[1]) {
1144 /* Handled by the normal mov below. Just drop out of the if condition */
1145 } else {
1146 WARN("Unsupported varying -> temp mov in <= ps_1_3\n");
1147 This->state = E_INVALIDARG;
1148 return;
1152 This->funcs->opcode(This, instr, token, buffer);
1153 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1154 This->funcs->srcreg(This, &instr->src[0], buffer);
1157 static const struct instr_handler_table ps_1_0123_handlers[] = {
1158 {BWRITERSIO_ADD, instr_handler},
1159 {BWRITERSIO_NOP, instr_handler},
1160 {BWRITERSIO_MOV, instr_ps_1_0123_mov},
1161 {BWRITERSIO_SUB, instr_handler},
1162 {BWRITERSIO_MAD, instr_handler},
1163 {BWRITERSIO_MUL, instr_handler},
1164 {BWRITERSIO_DP3, instr_handler},
1165 {BWRITERSIO_DP4, instr_handler},
1166 {BWRITERSIO_LRP, instr_handler},
1168 /* pshader instructions */
1169 {BWRITERSIO_CND, instr_handler},
1170 {BWRITERSIO_CMP, instr_handler},
1171 {BWRITERSIO_TEXKILL, instr_handler},
1172 {BWRITERSIO_TEX, instr_ps_1_0123_texld},
1173 {BWRITERSIO_TEXBEM, instr_handler},
1174 {BWRITERSIO_TEXBEML, instr_handler},
1175 {BWRITERSIO_TEXM3x2PAD, instr_handler},
1176 {BWRITERSIO_TEXM3x3PAD, instr_handler},
1177 {BWRITERSIO_TEXM3x3SPEC, instr_handler},
1178 {BWRITERSIO_TEXM3x3VSPEC, instr_handler},
1179 {BWRITERSIO_TEXM3x3TEX, instr_handler},
1180 {BWRITERSIO_TEXM3x3, instr_handler},
1181 {BWRITERSIO_TEXM3x2DEPTH, instr_handler},
1182 {BWRITERSIO_TEXM3x2TEX, instr_handler},
1183 {BWRITERSIO_TEXDP3, instr_handler},
1184 {BWRITERSIO_TEXDP3TEX, instr_handler},
1185 {BWRITERSIO_END, NULL},
1188 static const struct bytecode_backend ps_1_0123_backend = {
1189 ps_1_x_header,
1190 end,
1191 ps_1_0123_srcreg,
1192 ps_1_0123_dstreg,
1193 sm_1_x_opcode,
1194 ps_1_0123_handlers
1197 static void ps_1_4_srcreg(struct bc_writer *This, const struct shader_reg *reg,
1198 struct bytecode_buffer *buffer) {
1199 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1200 if(reg->rel_reg) {
1201 WARN("Relative addressing not supported in <= ps_3_0\n");
1202 This->state = E_INVALIDARG;
1203 return;
1206 switch(reg->type) {
1207 case BWRITERSPR_INPUT:
1208 token |= map_ps_input(This, reg);
1209 break;
1211 /* Can be mapped 1:1 */
1212 case BWRITERSPR_TEMP:
1213 case BWRITERSPR_CONST:
1214 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1215 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1216 break;
1218 default:
1219 WARN("Invalid register type for ps_1_4 shader\n");
1220 This->state = E_INVALIDARG;
1221 return;
1224 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1226 if(reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
1227 reg->srcmod == BWRITERSPSM_NOT) {
1228 WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
1229 This->state = E_INVALIDARG;
1230 return;
1232 token |= d3d9_srcmod(reg->srcmod);
1233 put_dword(buffer, token);
1236 static void ps_1_4_dstreg(struct bc_writer *This, const struct shader_reg *reg,
1237 struct bytecode_buffer *buffer,
1238 DWORD shift, DWORD mod) {
1239 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1241 if(reg->rel_reg) {
1242 WARN("Relative addressing not supported for destination registers\n");
1243 This->state = E_INVALIDARG;
1244 return;
1247 switch(reg->type) {
1248 case BWRITERSPR_TEMP: /* 1:1 mapping */
1249 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1250 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1251 break;
1253 /* For texkill */
1254 case BWRITERSPR_INPUT:
1255 token |= map_ps_input(This, reg);
1256 break;
1258 default:
1259 WARN("Invalid dest register type for 1.x pshader\n");
1260 This->state = E_INVALIDARG;
1261 return;
1264 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1265 token |= d3d9_dstmod(mod);
1267 token |= d3d9_writemask(reg->writemask);
1268 put_dword(buffer, token);
1271 static void instr_ps_1_4_mov(struct bc_writer *This,
1272 const struct instruction *instr,
1273 struct bytecode_buffer *buffer) {
1274 DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1276 if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
1277 if(instr->src[0].regnum == This->t_regnum[0] ||
1278 instr->src[0].regnum == This->t_regnum[1] ||
1279 instr->src[0].regnum == This->t_regnum[2] ||
1280 instr->src[0].regnum == This->t_regnum[3] ||
1281 instr->src[0].regnum == This->t_regnum[4] ||
1282 instr->src[0].regnum == This->t_regnum[5]) {
1283 /* Similar to a regular mov, but a different opcode */
1284 token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
1285 } else if(instr->src[0].regnum == This->v_regnum[0] ||
1286 instr->src[0].regnum == This->v_regnum[1]) {
1287 /* Handled by the normal mov below. Just drop out of the if condition */
1288 } else {
1289 WARN("Unsupported varying -> temp mov in ps_1_4\n");
1290 This->state = E_INVALIDARG;
1291 return;
1295 This->funcs->opcode(This, instr, token, buffer);
1296 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1297 This->funcs->srcreg(This, &instr->src[0], buffer);
1300 static void instr_ps_1_4_texld(struct bc_writer *This,
1301 const struct instruction *instr,
1302 struct bytecode_buffer *buffer) {
1303 if(instr->src[1].type != BWRITERSPR_SAMPLER ||
1304 instr->src[1].regnum > 5) {
1305 WARN("Unsupported sampler type %u regnum %u\n",
1306 instr->src[1].type, instr->src[1].regnum);
1307 This->state = E_INVALIDARG;
1308 return;
1309 } else if(instr->dst.type != BWRITERSPR_TEMP) {
1310 WARN("Can only sample into a temp register\n");
1311 This->state = E_INVALIDARG;
1312 return;
1315 if(instr->src[1].regnum != instr->dst.regnum) {
1316 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4\n",
1317 instr->src[1].regnum, instr->dst.regnum);
1318 This->state = E_INVALIDARG;
1319 return;
1322 This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1323 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1324 This->funcs->srcreg(This, &instr->src[0], buffer);
1327 static const struct instr_handler_table ps_1_4_handlers[] = {
1328 {BWRITERSIO_ADD, instr_handler},
1329 {BWRITERSIO_NOP, instr_handler},
1330 {BWRITERSIO_MOV, instr_ps_1_4_mov},
1331 {BWRITERSIO_SUB, instr_handler},
1332 {BWRITERSIO_MAD, instr_handler},
1333 {BWRITERSIO_MUL, instr_handler},
1334 {BWRITERSIO_DP3, instr_handler},
1335 {BWRITERSIO_DP4, instr_handler},
1336 {BWRITERSIO_LRP, instr_handler},
1338 /* pshader instructions */
1339 {BWRITERSIO_CND, instr_handler},
1340 {BWRITERSIO_CMP, instr_handler},
1341 {BWRITERSIO_TEXKILL, instr_handler},
1342 {BWRITERSIO_TEX, instr_ps_1_4_texld},
1343 {BWRITERSIO_TEXDEPTH, instr_handler},
1344 {BWRITERSIO_BEM, instr_handler},
1346 {BWRITERSIO_PHASE, instr_handler},
1347 {BWRITERSIO_END, NULL},
1350 static const struct bytecode_backend ps_1_4_backend = {
1351 ps_1_4_header,
1352 end,
1353 ps_1_4_srcreg,
1354 ps_1_4_dstreg,
1355 sm_1_x_opcode,
1356 ps_1_4_handlers
1359 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1360 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
1363 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1364 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
1367 static void vs_2_header(struct bc_writer *This,
1368 const struct bwriter_shader *shader,
1369 struct bytecode_buffer *buffer) {
1370 HRESULT hr;
1372 hr = vs_find_builtin_varyings(This, shader);
1373 if(FAILED(hr)) {
1374 This->state = hr;
1375 return;
1378 /* Declare the shader type and version */
1379 put_dword(buffer, This->version);
1381 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1382 write_constF(shader, buffer, TRUE);
1383 write_constB(shader, buffer, TRUE);
1384 write_constI(shader, buffer, TRUE);
1385 return;
1388 static void vs_2_srcreg(struct bc_writer *This,
1389 const struct shader_reg *reg,
1390 struct bytecode_buffer *buffer) {
1391 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1392 DWORD has_swizzle;
1393 DWORD component;
1394 DWORD d3d9reg;
1396 switch(reg->type) {
1397 case BWRITERSPR_OUTPUT:
1398 /* Map the swizzle to a writemask, the format expected
1399 by map_vs_output
1401 switch(reg->swizzle) {
1402 case BWRITERVS_SWIZZLE_X:
1403 component = BWRITERSP_WRITEMASK_0;
1404 break;
1405 case BWRITERVS_SWIZZLE_Y:
1406 component = BWRITERSP_WRITEMASK_1;
1407 break;
1408 case BWRITERVS_SWIZZLE_Z:
1409 component = BWRITERSP_WRITEMASK_2;
1410 break;
1411 case BWRITERVS_SWIZZLE_W:
1412 component = BWRITERSP_WRITEMASK_3;
1413 break;
1414 default:
1415 component = 0;
1417 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
1418 break;
1420 case BWRITERSPR_RASTOUT:
1421 case BWRITERSPR_ATTROUT:
1422 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1423 * but are unexpected. If we hit this path it might be due to an error.
1425 FIXME("Unexpected register type %u\n", reg->type);
1426 /* drop through */
1427 case BWRITERSPR_INPUT:
1428 case BWRITERSPR_TEMP:
1429 case BWRITERSPR_CONST:
1430 case BWRITERSPR_ADDR:
1431 case BWRITERSPR_CONSTINT:
1432 case BWRITERSPR_CONSTBOOL:
1433 case BWRITERSPR_LABEL:
1434 d3d9reg = d3d9_register(reg->type);
1435 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1436 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1437 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1438 break;
1440 case BWRITERSPR_LOOP:
1441 if(reg->regnum != 0) {
1442 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
1443 This->state = E_INVALIDARG;
1444 return;
1446 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1447 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1448 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1449 break;
1451 case BWRITERSPR_PREDICATE:
1452 if(This->version != BWRITERVS_VERSION(2, 1)){
1453 WARN("Predicate register is allowed only in vs_2_x\n");
1454 This->state = E_INVALIDARG;
1455 return;
1457 if(reg->regnum > 0) {
1458 WARN("Only predicate register 0 is supported\n");
1459 This->state = E_INVALIDARG;
1460 return;
1462 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1463 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1464 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1466 break;
1468 default:
1469 WARN("Invalid register type for 2.0 vshader\n");
1470 This->state = E_INVALIDARG;
1471 return;
1474 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1476 token |= d3d9_srcmod(reg->srcmod);
1478 if(reg->rel_reg)
1479 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1481 put_dword(buffer, token);
1483 /* vs_2_0 and newer write the register containing the index explicitly in the
1484 * binary code
1486 if(token & D3DVS_ADDRMODE_RELATIVE)
1487 vs_2_srcreg(This, reg->rel_reg, buffer);
1490 static void sm_2_opcode(struct bc_writer *This,
1491 const struct instruction *instr,
1492 DWORD token, struct bytecode_buffer *buffer) {
1493 /* From sm 2 onwards instruction length is encoded in the opcode field */
1494 int dsts = instr->has_dst ? 1 : 0;
1495 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
1496 if(instr->comptype)
1497 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1498 if(instr->has_predicate)
1499 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1500 put_dword(buffer,token);
1503 static const struct instr_handler_table vs_2_0_handlers[] = {
1504 {BWRITERSIO_ADD, instr_handler},
1505 {BWRITERSIO_NOP, instr_handler},
1506 {BWRITERSIO_MOV, instr_handler},
1507 {BWRITERSIO_SUB, instr_handler},
1508 {BWRITERSIO_MAD, instr_handler},
1509 {BWRITERSIO_MUL, instr_handler},
1510 {BWRITERSIO_RCP, instr_handler},
1511 {BWRITERSIO_RSQ, instr_handler},
1512 {BWRITERSIO_DP3, instr_handler},
1513 {BWRITERSIO_DP4, instr_handler},
1514 {BWRITERSIO_MIN, instr_handler},
1515 {BWRITERSIO_MAX, instr_handler},
1516 {BWRITERSIO_SLT, instr_handler},
1517 {BWRITERSIO_SGE, instr_handler},
1518 {BWRITERSIO_ABS, instr_handler},
1519 {BWRITERSIO_EXP, instr_handler},
1520 {BWRITERSIO_LOG, instr_handler},
1521 {BWRITERSIO_EXPP, instr_handler},
1522 {BWRITERSIO_LOGP, instr_handler},
1523 {BWRITERSIO_DST, instr_handler},
1524 {BWRITERSIO_LRP, instr_handler},
1525 {BWRITERSIO_FRC, instr_handler},
1526 {BWRITERSIO_CRS, instr_handler},
1527 {BWRITERSIO_SGN, instr_handler},
1528 {BWRITERSIO_NRM, instr_handler},
1529 {BWRITERSIO_SINCOS, instr_handler},
1530 {BWRITERSIO_M4x4, instr_handler},
1531 {BWRITERSIO_M4x3, instr_handler},
1532 {BWRITERSIO_M3x4, instr_handler},
1533 {BWRITERSIO_M3x3, instr_handler},
1534 {BWRITERSIO_M3x2, instr_handler},
1535 {BWRITERSIO_LIT, instr_handler},
1536 {BWRITERSIO_POW, instr_handler},
1537 {BWRITERSIO_MOVA, instr_handler},
1539 {BWRITERSIO_CALL, instr_handler},
1540 {BWRITERSIO_CALLNZ, instr_handler},
1541 {BWRITERSIO_REP, instr_handler},
1542 {BWRITERSIO_ENDREP, instr_handler},
1543 {BWRITERSIO_IF, instr_handler},
1544 {BWRITERSIO_LABEL, instr_handler},
1545 {BWRITERSIO_ELSE, instr_handler},
1546 {BWRITERSIO_ENDIF, instr_handler},
1547 {BWRITERSIO_LOOP, instr_handler},
1548 {BWRITERSIO_RET, instr_handler},
1549 {BWRITERSIO_ENDLOOP, instr_handler},
1551 {BWRITERSIO_END, NULL},
1554 static const struct bytecode_backend vs_2_0_backend = {
1555 vs_2_header,
1556 end,
1557 vs_2_srcreg,
1558 vs_12_dstreg,
1559 sm_2_opcode,
1560 vs_2_0_handlers
1563 static const struct instr_handler_table vs_2_x_handlers[] = {
1564 {BWRITERSIO_ADD, instr_handler},
1565 {BWRITERSIO_NOP, instr_handler},
1566 {BWRITERSIO_MOV, instr_handler},
1567 {BWRITERSIO_SUB, instr_handler},
1568 {BWRITERSIO_MAD, instr_handler},
1569 {BWRITERSIO_MUL, instr_handler},
1570 {BWRITERSIO_RCP, instr_handler},
1571 {BWRITERSIO_RSQ, instr_handler},
1572 {BWRITERSIO_DP3, instr_handler},
1573 {BWRITERSIO_DP4, instr_handler},
1574 {BWRITERSIO_MIN, instr_handler},
1575 {BWRITERSIO_MAX, instr_handler},
1576 {BWRITERSIO_SLT, instr_handler},
1577 {BWRITERSIO_SGE, instr_handler},
1578 {BWRITERSIO_ABS, instr_handler},
1579 {BWRITERSIO_EXP, instr_handler},
1580 {BWRITERSIO_LOG, instr_handler},
1581 {BWRITERSIO_EXPP, instr_handler},
1582 {BWRITERSIO_LOGP, instr_handler},
1583 {BWRITERSIO_DST, instr_handler},
1584 {BWRITERSIO_LRP, instr_handler},
1585 {BWRITERSIO_FRC, instr_handler},
1586 {BWRITERSIO_CRS, instr_handler},
1587 {BWRITERSIO_SGN, instr_handler},
1588 {BWRITERSIO_NRM, instr_handler},
1589 {BWRITERSIO_SINCOS, instr_handler},
1590 {BWRITERSIO_M4x4, instr_handler},
1591 {BWRITERSIO_M4x3, instr_handler},
1592 {BWRITERSIO_M3x4, instr_handler},
1593 {BWRITERSIO_M3x3, instr_handler},
1594 {BWRITERSIO_M3x2, instr_handler},
1595 {BWRITERSIO_LIT, instr_handler},
1596 {BWRITERSIO_POW, instr_handler},
1597 {BWRITERSIO_MOVA, instr_handler},
1599 {BWRITERSIO_CALL, instr_handler},
1600 {BWRITERSIO_CALLNZ, instr_handler},
1601 {BWRITERSIO_REP, instr_handler},
1602 {BWRITERSIO_ENDREP, instr_handler},
1603 {BWRITERSIO_IF, instr_handler},
1604 {BWRITERSIO_LABEL, instr_handler},
1605 {BWRITERSIO_IFC, instr_handler},
1606 {BWRITERSIO_ELSE, instr_handler},
1607 {BWRITERSIO_ENDIF, instr_handler},
1608 {BWRITERSIO_BREAK, instr_handler},
1609 {BWRITERSIO_BREAKC, instr_handler},
1610 {BWRITERSIO_LOOP, instr_handler},
1611 {BWRITERSIO_RET, instr_handler},
1612 {BWRITERSIO_ENDLOOP, instr_handler},
1614 {BWRITERSIO_SETP, instr_handler},
1615 {BWRITERSIO_BREAKP, instr_handler},
1617 {BWRITERSIO_END, NULL},
1620 static const struct bytecode_backend vs_2_x_backend = {
1621 vs_2_header,
1622 end,
1623 vs_2_srcreg,
1624 vs_12_dstreg,
1625 sm_2_opcode,
1626 vs_2_x_handlers
1629 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1630 DWORD i;
1631 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1632 DWORD token;
1633 const DWORD reg = (1<<31) |
1634 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
1635 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
1636 D3DSP_WRITEMASK_ALL;
1638 for(i = 0; i < shader->num_samplers; i++) {
1639 /* Write the DCL instruction */
1640 put_dword(buffer, instr_dcl);
1641 token = (1<<31);
1642 /* Already shifted */
1643 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
1644 put_dword(buffer, token);
1645 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1646 token |= d3d9_dstmod(shader->samplers[i].mod);
1647 put_dword(buffer, token);
1651 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1652 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1653 if(FAILED(hr)) {
1654 This->state = hr;
1655 return;
1658 /* Declare the shader type and version */
1659 put_dword(buffer, This->version);
1660 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1661 write_samplers(shader, buffer);
1662 write_constF(shader, buffer, TRUE);
1663 write_constB(shader, buffer, TRUE);
1664 write_constI(shader, buffer, TRUE);
1667 static void ps_2_srcreg(struct bc_writer *This,
1668 const struct shader_reg *reg,
1669 struct bytecode_buffer *buffer) {
1670 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1671 DWORD d3d9reg;
1672 if(reg->rel_reg) {
1673 WARN("Relative addressing not supported in <= ps_3_0\n");
1674 This->state = E_INVALIDARG;
1675 return;
1678 switch(reg->type) {
1679 case BWRITERSPR_INPUT:
1680 token |= map_ps_input(This, reg);
1681 break;
1683 /* Can be mapped 1:1 */
1684 case BWRITERSPR_TEMP:
1685 case BWRITERSPR_CONST:
1686 case BWRITERSPR_COLOROUT:
1687 case BWRITERSPR_CONSTBOOL:
1688 case BWRITERSPR_CONSTINT:
1689 case BWRITERSPR_SAMPLER:
1690 case BWRITERSPR_LABEL:
1691 case BWRITERSPR_DEPTHOUT:
1692 d3d9reg = d3d9_register(reg->type);
1693 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1694 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1695 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1696 break;
1698 case BWRITERSPR_PREDICATE:
1699 if(This->version != BWRITERPS_VERSION(2, 1)){
1700 WARN("Predicate register not supported in ps_2_0\n");
1701 This->state = E_INVALIDARG;
1703 if(reg->regnum) {
1704 WARN("Predicate register with regnum %u not supported\n",
1705 reg->regnum);
1706 This->state = E_INVALIDARG;
1708 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1709 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1710 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1711 break;
1713 default:
1714 WARN("Invalid register type for ps_2_0 shader\n");
1715 This->state = E_INVALIDARG;
1716 return;
1719 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1721 token |= d3d9_srcmod(reg->srcmod);
1722 put_dword(buffer, token);
1725 static void ps_2_0_dstreg(struct bc_writer *This,
1726 const struct shader_reg *reg,
1727 struct bytecode_buffer *buffer,
1728 DWORD shift, DWORD mod) {
1729 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1730 DWORD d3d9reg;
1732 if(reg->rel_reg) {
1733 WARN("Relative addressing not supported for destination registers\n");
1734 This->state = E_INVALIDARG;
1735 return;
1738 switch(reg->type) {
1739 case BWRITERSPR_TEMP: /* 1:1 mapping */
1740 case BWRITERSPR_COLOROUT:
1741 case BWRITERSPR_DEPTHOUT:
1742 d3d9reg = d3d9_register(reg->type);
1743 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1744 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1745 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1746 break;
1748 case BWRITERSPR_PREDICATE:
1749 if(This->version != BWRITERPS_VERSION(2, 1)){
1750 WARN("Predicate register not supported in ps_2_0\n");
1751 This->state = E_INVALIDARG;
1753 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1754 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1755 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1756 break;
1758 /* texkill uses the input register as a destination parameter */
1759 case BWRITERSPR_INPUT:
1760 token |= map_ps_input(This, reg);
1761 break;
1763 default:
1764 WARN("Invalid dest register type for 2.x pshader\n");
1765 This->state = E_INVALIDARG;
1766 return;
1769 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1770 token |= d3d9_dstmod(mod);
1772 token |= d3d9_writemask(reg->writemask);
1773 put_dword(buffer, token);
1776 static const struct instr_handler_table ps_2_0_handlers[] = {
1777 {BWRITERSIO_ADD, instr_handler},
1778 {BWRITERSIO_NOP, instr_handler},
1779 {BWRITERSIO_MOV, instr_handler},
1780 {BWRITERSIO_SUB, instr_handler},
1781 {BWRITERSIO_MAD, instr_handler},
1782 {BWRITERSIO_MUL, instr_handler},
1783 {BWRITERSIO_RCP, instr_handler},
1784 {BWRITERSIO_RSQ, instr_handler},
1785 {BWRITERSIO_DP3, instr_handler},
1786 {BWRITERSIO_DP4, instr_handler},
1787 {BWRITERSIO_MIN, instr_handler},
1788 {BWRITERSIO_MAX, instr_handler},
1789 {BWRITERSIO_ABS, instr_handler},
1790 {BWRITERSIO_EXP, instr_handler},
1791 {BWRITERSIO_LOG, instr_handler},
1792 {BWRITERSIO_EXPP, instr_handler},
1793 {BWRITERSIO_LOGP, instr_handler},
1794 {BWRITERSIO_LRP, instr_handler},
1795 {BWRITERSIO_FRC, instr_handler},
1796 {BWRITERSIO_CRS, instr_handler},
1797 {BWRITERSIO_NRM, instr_handler},
1798 {BWRITERSIO_SINCOS, instr_handler},
1799 {BWRITERSIO_M4x4, instr_handler},
1800 {BWRITERSIO_M4x3, instr_handler},
1801 {BWRITERSIO_M3x4, instr_handler},
1802 {BWRITERSIO_M3x3, instr_handler},
1803 {BWRITERSIO_M3x2, instr_handler},
1804 {BWRITERSIO_POW, instr_handler},
1805 {BWRITERSIO_DP2ADD, instr_handler},
1806 {BWRITERSIO_CMP, instr_handler},
1808 {BWRITERSIO_TEX, instr_handler},
1809 {BWRITERSIO_TEXLDP, instr_handler},
1810 {BWRITERSIO_TEXLDB, instr_handler},
1811 {BWRITERSIO_TEXKILL, instr_handler},
1813 {BWRITERSIO_END, NULL},
1816 static const struct bytecode_backend ps_2_0_backend = {
1817 ps_2_header,
1818 end,
1819 ps_2_srcreg,
1820 ps_2_0_dstreg,
1821 sm_2_opcode,
1822 ps_2_0_handlers
1825 static const struct instr_handler_table ps_2_x_handlers[] = {
1826 {BWRITERSIO_ADD, instr_handler},
1827 {BWRITERSIO_NOP, instr_handler},
1828 {BWRITERSIO_MOV, instr_handler},
1829 {BWRITERSIO_SUB, instr_handler},
1830 {BWRITERSIO_MAD, instr_handler},
1831 {BWRITERSIO_MUL, instr_handler},
1832 {BWRITERSIO_RCP, instr_handler},
1833 {BWRITERSIO_RSQ, instr_handler},
1834 {BWRITERSIO_DP3, instr_handler},
1835 {BWRITERSIO_DP4, instr_handler},
1836 {BWRITERSIO_MIN, instr_handler},
1837 {BWRITERSIO_MAX, instr_handler},
1838 {BWRITERSIO_ABS, instr_handler},
1839 {BWRITERSIO_EXP, instr_handler},
1840 {BWRITERSIO_LOG, instr_handler},
1841 {BWRITERSIO_EXPP, instr_handler},
1842 {BWRITERSIO_LOGP, instr_handler},
1843 {BWRITERSIO_LRP, instr_handler},
1844 {BWRITERSIO_FRC, instr_handler},
1845 {BWRITERSIO_CRS, instr_handler},
1846 {BWRITERSIO_NRM, instr_handler},
1847 {BWRITERSIO_SINCOS, instr_handler},
1848 {BWRITERSIO_M4x4, instr_handler},
1849 {BWRITERSIO_M4x3, instr_handler},
1850 {BWRITERSIO_M3x4, instr_handler},
1851 {BWRITERSIO_M3x3, instr_handler},
1852 {BWRITERSIO_M3x2, instr_handler},
1853 {BWRITERSIO_POW, instr_handler},
1854 {BWRITERSIO_DP2ADD, instr_handler},
1855 {BWRITERSIO_CMP, instr_handler},
1857 {BWRITERSIO_CALL, instr_handler},
1858 {BWRITERSIO_CALLNZ, instr_handler},
1859 {BWRITERSIO_REP, instr_handler},
1860 {BWRITERSIO_ENDREP, instr_handler},
1861 {BWRITERSIO_IF, instr_handler},
1862 {BWRITERSIO_LABEL, instr_handler},
1863 {BWRITERSIO_IFC, instr_handler},
1864 {BWRITERSIO_ELSE, instr_handler},
1865 {BWRITERSIO_ENDIF, instr_handler},
1866 {BWRITERSIO_BREAK, instr_handler},
1867 {BWRITERSIO_BREAKC, instr_handler},
1868 {BWRITERSIO_RET, instr_handler},
1870 {BWRITERSIO_TEX, instr_handler},
1871 {BWRITERSIO_TEXLDP, instr_handler},
1872 {BWRITERSIO_TEXLDB, instr_handler},
1873 {BWRITERSIO_TEXKILL, instr_handler},
1874 {BWRITERSIO_DSX, instr_handler},
1875 {BWRITERSIO_DSY, instr_handler},
1877 {BWRITERSIO_SETP, instr_handler},
1878 {BWRITERSIO_BREAKP, instr_handler},
1880 {BWRITERSIO_TEXLDD, instr_handler},
1882 {BWRITERSIO_END, NULL},
1885 static const struct bytecode_backend ps_2_x_backend = {
1886 ps_2_header,
1887 end,
1888 ps_2_srcreg,
1889 ps_2_0_dstreg,
1890 sm_2_opcode,
1891 ps_2_x_handlers
1894 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1895 /* Declare the shader type and version */
1896 put_dword(buffer, This->version);
1898 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1899 write_declarations(This, buffer, TRUE, shader->outputs, shader->num_outputs, BWRITERSPR_OUTPUT);
1900 write_constF(shader, buffer, TRUE);
1901 write_constB(shader, buffer, TRUE);
1902 write_constI(shader, buffer, TRUE);
1903 write_samplers(shader, buffer);
1904 return;
1907 static void sm_3_srcreg(struct bc_writer *This,
1908 const struct shader_reg *reg,
1909 struct bytecode_buffer *buffer) {
1910 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1911 DWORD d3d9reg;
1913 d3d9reg = d3d9_register(reg->type);
1914 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1915 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1916 token |= reg->regnum & D3DSP_REGNUM_MASK;
1918 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
1919 token |= d3d9_srcmod(reg->srcmod);
1921 if(reg->rel_reg) {
1922 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
1923 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
1924 This->state = E_INVALIDARG;
1925 return;
1927 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
1928 reg->rel_reg->type == BWRITERSPR_LOOP) &&
1929 reg->rel_reg->regnum == 0) {
1930 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1931 } else {
1932 WARN("Unsupported relative addressing register\n");
1933 This->state = E_INVALIDARG;
1934 return;
1938 put_dword(buffer, token);
1940 /* vs_2_0 and newer write the register containing the index explicitly in the
1941 * binary code
1943 if(token & D3DVS_ADDRMODE_RELATIVE) {
1944 sm_3_srcreg(This, reg->rel_reg, buffer);
1948 static void sm_3_dstreg(struct bc_writer *This,
1949 const struct shader_reg *reg,
1950 struct bytecode_buffer *buffer,
1951 DWORD shift, DWORD mod) {
1952 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1953 DWORD d3d9reg;
1955 if(reg->rel_reg) {
1956 if(This->version == BWRITERVS_VERSION(3, 0) &&
1957 reg->type == BWRITERSPR_OUTPUT) {
1958 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1959 } else {
1960 WARN("Relative addressing not supported for this shader type or register type\n");
1961 This->state = E_INVALIDARG;
1962 return;
1966 d3d9reg = d3d9_register(reg->type);
1967 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1968 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1969 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1971 token |= d3d9_dstmod(mod);
1973 token |= d3d9_writemask(reg->writemask);
1974 put_dword(buffer, token);
1976 /* vs_2_0 and newer write the register containing the index explicitly in the
1977 * binary code
1979 if(token & D3DVS_ADDRMODE_RELATIVE) {
1980 sm_3_srcreg(This, reg->rel_reg, buffer);
1984 static const struct instr_handler_table vs_3_handlers[] = {
1985 {BWRITERSIO_ADD, instr_handler},
1986 {BWRITERSIO_NOP, instr_handler},
1987 {BWRITERSIO_MOV, instr_handler},
1988 {BWRITERSIO_SUB, instr_handler},
1989 {BWRITERSIO_MAD, instr_handler},
1990 {BWRITERSIO_MUL, instr_handler},
1991 {BWRITERSIO_RCP, instr_handler},
1992 {BWRITERSIO_RSQ, instr_handler},
1993 {BWRITERSIO_DP3, instr_handler},
1994 {BWRITERSIO_DP4, instr_handler},
1995 {BWRITERSIO_MIN, instr_handler},
1996 {BWRITERSIO_MAX, instr_handler},
1997 {BWRITERSIO_SLT, instr_handler},
1998 {BWRITERSIO_SGE, instr_handler},
1999 {BWRITERSIO_ABS, instr_handler},
2000 {BWRITERSIO_EXP, instr_handler},
2001 {BWRITERSIO_LOG, instr_handler},
2002 {BWRITERSIO_EXPP, instr_handler},
2003 {BWRITERSIO_LOGP, instr_handler},
2004 {BWRITERSIO_DST, instr_handler},
2005 {BWRITERSIO_LRP, instr_handler},
2006 {BWRITERSIO_FRC, instr_handler},
2007 {BWRITERSIO_CRS, instr_handler},
2008 {BWRITERSIO_SGN, instr_handler},
2009 {BWRITERSIO_NRM, instr_handler},
2010 {BWRITERSIO_SINCOS, instr_handler},
2011 {BWRITERSIO_M4x4, instr_handler},
2012 {BWRITERSIO_M4x3, instr_handler},
2013 {BWRITERSIO_M3x4, instr_handler},
2014 {BWRITERSIO_M3x3, instr_handler},
2015 {BWRITERSIO_M3x2, instr_handler},
2016 {BWRITERSIO_LIT, instr_handler},
2017 {BWRITERSIO_POW, instr_handler},
2018 {BWRITERSIO_MOVA, instr_handler},
2020 {BWRITERSIO_CALL, instr_handler},
2021 {BWRITERSIO_CALLNZ, instr_handler},
2022 {BWRITERSIO_REP, instr_handler},
2023 {BWRITERSIO_ENDREP, instr_handler},
2024 {BWRITERSIO_IF, instr_handler},
2025 {BWRITERSIO_LABEL, instr_handler},
2026 {BWRITERSIO_IFC, instr_handler},
2027 {BWRITERSIO_ELSE, instr_handler},
2028 {BWRITERSIO_ENDIF, instr_handler},
2029 {BWRITERSIO_BREAK, instr_handler},
2030 {BWRITERSIO_BREAKC, instr_handler},
2031 {BWRITERSIO_LOOP, instr_handler},
2032 {BWRITERSIO_RET, instr_handler},
2033 {BWRITERSIO_ENDLOOP, instr_handler},
2035 {BWRITERSIO_SETP, instr_handler},
2036 {BWRITERSIO_BREAKP, instr_handler},
2037 {BWRITERSIO_TEXLDL, instr_handler},
2039 {BWRITERSIO_END, NULL},
2042 static const struct bytecode_backend vs_3_backend = {
2043 sm_3_header,
2044 end,
2045 sm_3_srcreg,
2046 sm_3_dstreg,
2047 sm_2_opcode,
2048 vs_3_handlers
2051 static const struct instr_handler_table ps_3_handlers[] = {
2052 {BWRITERSIO_ADD, instr_handler},
2053 {BWRITERSIO_NOP, instr_handler},
2054 {BWRITERSIO_MOV, instr_handler},
2055 {BWRITERSIO_SUB, instr_handler},
2056 {BWRITERSIO_MAD, instr_handler},
2057 {BWRITERSIO_MUL, instr_handler},
2058 {BWRITERSIO_RCP, instr_handler},
2059 {BWRITERSIO_RSQ, instr_handler},
2060 {BWRITERSIO_DP3, instr_handler},
2061 {BWRITERSIO_DP4, instr_handler},
2062 {BWRITERSIO_MIN, instr_handler},
2063 {BWRITERSIO_MAX, instr_handler},
2064 {BWRITERSIO_ABS, instr_handler},
2065 {BWRITERSIO_EXP, instr_handler},
2066 {BWRITERSIO_LOG, instr_handler},
2067 {BWRITERSIO_EXPP, instr_handler},
2068 {BWRITERSIO_LOGP, instr_handler},
2069 {BWRITERSIO_LRP, instr_handler},
2070 {BWRITERSIO_FRC, instr_handler},
2071 {BWRITERSIO_CRS, instr_handler},
2072 {BWRITERSIO_NRM, instr_handler},
2073 {BWRITERSIO_SINCOS, instr_handler},
2074 {BWRITERSIO_M4x4, instr_handler},
2075 {BWRITERSIO_M4x3, instr_handler},
2076 {BWRITERSIO_M3x4, instr_handler},
2077 {BWRITERSIO_M3x3, instr_handler},
2078 {BWRITERSIO_M3x2, instr_handler},
2079 {BWRITERSIO_POW, instr_handler},
2080 {BWRITERSIO_DP2ADD, instr_handler},
2081 {BWRITERSIO_CMP, instr_handler},
2083 {BWRITERSIO_CALL, instr_handler},
2084 {BWRITERSIO_CALLNZ, instr_handler},
2085 {BWRITERSIO_REP, instr_handler},
2086 {BWRITERSIO_ENDREP, instr_handler},
2087 {BWRITERSIO_IF, instr_handler},
2088 {BWRITERSIO_LABEL, instr_handler},
2089 {BWRITERSIO_IFC, instr_handler},
2090 {BWRITERSIO_ELSE, instr_handler},
2091 {BWRITERSIO_ENDIF, instr_handler},
2092 {BWRITERSIO_BREAK, instr_handler},
2093 {BWRITERSIO_BREAKC, instr_handler},
2094 {BWRITERSIO_LOOP, instr_handler},
2095 {BWRITERSIO_RET, instr_handler},
2096 {BWRITERSIO_ENDLOOP, instr_handler},
2098 {BWRITERSIO_SETP, instr_handler},
2099 {BWRITERSIO_BREAKP, instr_handler},
2100 {BWRITERSIO_TEXLDL, instr_handler},
2102 {BWRITERSIO_TEX, instr_handler},
2103 {BWRITERSIO_TEXLDP, instr_handler},
2104 {BWRITERSIO_TEXLDB, instr_handler},
2105 {BWRITERSIO_TEXKILL, instr_handler},
2106 {BWRITERSIO_DSX, instr_handler},
2107 {BWRITERSIO_DSY, instr_handler},
2108 {BWRITERSIO_TEXLDD, instr_handler},
2110 {BWRITERSIO_END, NULL},
2113 static const struct bytecode_backend ps_3_backend = {
2114 sm_3_header,
2115 end,
2116 sm_3_srcreg,
2117 sm_3_dstreg,
2118 sm_2_opcode,
2119 ps_3_handlers
2122 static void init_vs10_dx9_writer(struct bc_writer *writer) {
2123 TRACE("Creating DirectX9 vertex shader 1.0 writer\n");
2124 writer->funcs = &vs_1_x_backend;
2127 static void init_vs11_dx9_writer(struct bc_writer *writer) {
2128 TRACE("Creating DirectX9 vertex shader 1.1 writer\n");
2129 writer->funcs = &vs_1_x_backend;
2132 static void init_vs20_dx9_writer(struct bc_writer *writer) {
2133 TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
2134 writer->funcs = &vs_2_0_backend;
2137 static void init_vs2x_dx9_writer(struct bc_writer *writer) {
2138 TRACE("Creating DirectX9 vertex shader 2.x writer\n");
2139 writer->funcs = &vs_2_x_backend;
2142 static void init_vs30_dx9_writer(struct bc_writer *writer) {
2143 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
2144 writer->funcs = &vs_3_backend;
2147 static void init_ps10_dx9_writer(struct bc_writer *writer) {
2148 TRACE("Creating DirectX9 pixel shader 1.0 writer\n");
2149 writer->funcs = &ps_1_0123_backend;
2152 static void init_ps11_dx9_writer(struct bc_writer *writer) {
2153 TRACE("Creating DirectX9 pixel shader 1.1 writer\n");
2154 writer->funcs = &ps_1_0123_backend;
2157 static void init_ps12_dx9_writer(struct bc_writer *writer) {
2158 TRACE("Creating DirectX9 pixel shader 1.2 writer\n");
2159 writer->funcs = &ps_1_0123_backend;
2162 static void init_ps13_dx9_writer(struct bc_writer *writer) {
2163 TRACE("Creating DirectX9 pixel shader 1.3 writer\n");
2164 writer->funcs = &ps_1_0123_backend;
2167 static void init_ps14_dx9_writer(struct bc_writer *writer) {
2168 TRACE("Creating DirectX9 pixel shader 1.4 writer\n");
2169 writer->funcs = &ps_1_4_backend;
2172 static void init_ps20_dx9_writer(struct bc_writer *writer) {
2173 TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
2174 writer->funcs = &ps_2_0_backend;
2177 static void init_ps2x_dx9_writer(struct bc_writer *writer) {
2178 TRACE("Creating DirectX9 pixel shader 2.x writer\n");
2179 writer->funcs = &ps_2_x_backend;
2182 static void init_ps30_dx9_writer(struct bc_writer *writer) {
2183 TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
2184 writer->funcs = &ps_3_backend;
2187 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
2188 struct bc_writer *ret = asm_alloc(sizeof(*ret));
2190 if(!ret) {
2191 WARN("Failed to allocate a bytecode writer instance\n");
2192 return NULL;
2195 switch(version) {
2196 case BWRITERVS_VERSION(1, 0):
2197 if(dxversion != 9) {
2198 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
2199 goto fail;
2201 init_vs10_dx9_writer(ret);
2202 break;
2203 case BWRITERVS_VERSION(1, 1):
2204 if(dxversion != 9) {
2205 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
2206 goto fail;
2208 init_vs11_dx9_writer(ret);
2209 break;
2210 case BWRITERVS_VERSION(2, 0):
2211 if(dxversion != 9) {
2212 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
2213 goto fail;
2215 init_vs20_dx9_writer(ret);
2216 break;
2217 case BWRITERVS_VERSION(2, 1):
2218 if(dxversion != 9) {
2219 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
2220 goto fail;
2222 init_vs2x_dx9_writer(ret);
2223 break;
2224 case BWRITERVS_VERSION(3, 0):
2225 if(dxversion != 9) {
2226 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
2227 goto fail;
2229 init_vs30_dx9_writer(ret);
2230 break;
2232 case BWRITERPS_VERSION(1, 0):
2233 if(dxversion != 9) {
2234 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
2235 goto fail;
2237 init_ps10_dx9_writer(ret);
2238 break;
2239 case BWRITERPS_VERSION(1, 1):
2240 if(dxversion != 9) {
2241 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
2242 goto fail;
2244 init_ps11_dx9_writer(ret);
2245 break;
2246 case BWRITERPS_VERSION(1, 2):
2247 if(dxversion != 9) {
2248 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
2249 goto fail;
2251 init_ps12_dx9_writer(ret);
2252 break;
2253 case BWRITERPS_VERSION(1, 3):
2254 if(dxversion != 9) {
2255 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
2256 goto fail;
2258 init_ps13_dx9_writer(ret);
2259 break;
2260 case BWRITERPS_VERSION(1, 4):
2261 if(dxversion != 9) {
2262 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
2263 goto fail;
2265 init_ps14_dx9_writer(ret);
2266 break;
2268 case BWRITERPS_VERSION(2, 0):
2269 if(dxversion != 9) {
2270 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
2271 goto fail;
2273 init_ps20_dx9_writer(ret);
2274 break;
2276 case BWRITERPS_VERSION(2, 1):
2277 if(dxversion != 9) {
2278 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
2279 goto fail;
2281 init_ps2x_dx9_writer(ret);
2282 break;
2284 case BWRITERPS_VERSION(3, 0):
2285 if(dxversion != 9) {
2286 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
2287 goto fail;
2289 init_ps30_dx9_writer(ret);
2290 break;
2292 default:
2293 WARN("Unexpected shader version requested: %08x\n", version);
2294 goto fail;
2296 ret->version = version;
2297 return ret;
2299 fail:
2300 asm_free(ret);
2301 return NULL;
2304 static HRESULT call_instr_handler(struct bc_writer *writer,
2305 const struct instruction *instr,
2306 struct bytecode_buffer *buffer) {
2307 DWORD i=0;
2309 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
2310 if(instr->opcode == writer->funcs->instructions[i].opcode) {
2311 if(!writer->funcs->instructions[i].func) {
2312 WARN("Opcode %u not supported by this profile\n", instr->opcode);
2313 return E_INVALIDARG;
2315 writer->funcs->instructions[i].func(writer, instr, buffer);
2316 return S_OK;
2318 i++;
2321 FIXME("Unhandled instruction %u - %s\n", instr->opcode,
2322 debug_print_opcode(instr->opcode));
2323 return E_INVALIDARG;
2326 /* SlWriteBytecode (wineshader.@)
2328 * Writes shader version specific bytecode from the shader passed in.
2329 * The returned bytecode can be passed to the Direct3D runtime like
2330 * IDirect3DDevice9::Create*Shader.
2332 * Parameters:
2333 * shader: Shader to translate into bytecode
2334 * version: Shader version to generate(d3d version token)
2335 * dxversion: DirectX version the code targets
2336 * result: the resulting shader bytecode
2338 * Return values:
2339 * S_OK on success
2341 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
2342 struct bc_writer *writer;
2343 struct bytecode_buffer *buffer = NULL;
2344 HRESULT hr;
2345 unsigned int i;
2347 if(!shader){
2348 ERR("NULL shader structure, aborting\n");
2349 return E_FAIL;
2351 writer = create_writer(shader->version, dxversion);
2352 *result = NULL;
2354 if(!writer) {
2355 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
2356 WARN("or out of memory\n");
2357 hr = E_FAIL;
2358 goto error;
2361 buffer = allocate_buffer();
2362 if(!buffer) {
2363 WARN("Failed to allocate a buffer for the shader bytecode\n");
2364 hr = E_FAIL;
2365 goto error;
2368 writer->funcs->header(writer, shader, buffer);
2369 if(FAILED(writer->state)) {
2370 hr = writer->state;
2371 goto error;
2374 for(i = 0; i < shader->num_instrs; i++) {
2375 hr = call_instr_handler(writer, shader->instr[i], buffer);
2376 if(FAILED(hr)) {
2377 goto error;
2381 if(FAILED(writer->state)) {
2382 hr = writer->state;
2383 goto error;
2386 writer->funcs->end(writer, shader, buffer);
2388 if(FAILED(buffer->state)) {
2389 hr = buffer->state;
2390 goto error;
2393 /* Cut off unneeded memory from the result buffer */
2394 *result = asm_realloc(buffer->data,
2395 sizeof(DWORD) * buffer->size);
2396 if(!*result) {
2397 *result = buffer->data;
2399 buffer->data = NULL;
2400 hr = S_OK;
2402 error:
2403 if(buffer) {
2404 asm_free(buffer->data);
2405 asm_free(buffer);
2407 asm_free(writer);
2408 return hr;
2411 void SlDeleteShader(struct bwriter_shader *shader) {
2412 unsigned int i, j;
2414 TRACE("Deleting shader %p\n", shader);
2416 for(i = 0; i < shader->num_cf; i++) {
2417 asm_free(shader->constF[i]);
2419 asm_free(shader->constF);
2420 for(i = 0; i < shader->num_ci; i++) {
2421 asm_free(shader->constI[i]);
2423 asm_free(shader->constI);
2424 for(i = 0; i < shader->num_cb; i++) {
2425 asm_free(shader->constB[i]);
2427 asm_free(shader->constB);
2429 asm_free(shader->inputs);
2430 asm_free(shader->outputs);
2431 asm_free(shader->samplers);
2433 for(i = 0; i < shader->num_instrs; i++) {
2434 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
2435 asm_free(shader->instr[i]->src[j].rel_reg);
2437 asm_free(shader->instr[i]->src);
2438 asm_free(shader->instr[i]);
2440 asm_free(shader->instr);
2442 asm_free(shader);