browseui: Add Danish translation.
[wine/testsucceed.git] / dlls / d3dx9_36 / bytecodewriter.c
blob84fefee6be1a1734b2f5865e13a63115be606776
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, DWORD usage_idx, DWORD mod, BOOL output, DWORD regnum, DWORD writemask) {
213 unsigned int *num;
214 struct declaration **decl;
215 unsigned int i;
217 if(!shader) return FALSE;
219 if(output) {
220 num = &shader->num_outputs;
221 decl = &shader->outputs;
222 } else {
223 num = &shader->num_inputs;
224 decl = &shader->inputs;
227 if(*num == 0) {
228 *decl = asm_alloc(sizeof(**decl));
229 if(!*decl) {
230 ERR("Error allocating declarations array\n");
231 return FALSE;
233 } else {
234 struct declaration *newdecl;
235 for(i = 0; i < *num; i++) {
236 if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
237 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
238 regnum, (*decl)[i].writemask & writemask);
242 newdecl = asm_realloc(*decl,
243 sizeof(**decl) * ((*num) + 1));
244 if(!newdecl) {
245 ERR("Error reallocating declarations array\n");
246 return FALSE;
248 *decl = newdecl;
250 (*decl)[*num].usage = usage;
251 (*decl)[*num].usage_idx = usage_idx;
252 (*decl)[*num].regnum = regnum;
253 (*decl)[*num].mod = mod;
254 (*decl)[*num].writemask = writemask;
255 (*num)++;
257 return TRUE;
260 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD mod, DWORD regnum) {
261 unsigned int i;
263 if(!shader) return FALSE;
265 if(shader->num_samplers == 0) {
266 shader->samplers = asm_alloc(sizeof(*shader->samplers));
267 if(!shader->samplers) {
268 ERR("Error allocating samplers array\n");
269 return FALSE;
271 } else {
272 struct samplerdecl *newarray;
274 for(i = 0; i < shader->num_samplers; i++) {
275 if(shader->samplers[i].regnum == regnum) {
276 WARN("Sampler %u already declared\n", regnum);
277 /* This is not an error as far as the assembler is concerned.
278 * Direct3D might refuse to load the compiled shader though
283 newarray = asm_realloc(shader->samplers,
284 sizeof(*shader->samplers) * (shader->num_samplers + 1));
285 if(!newarray) {
286 ERR("Error reallocating samplers array\n");
287 return FALSE;
289 shader->samplers = newarray;
292 shader->samplers[shader->num_samplers].type = samptype;
293 shader->samplers[shader->num_samplers].mod = mod;
294 shader->samplers[shader->num_samplers].regnum = regnum;
295 shader->num_samplers++;
296 return TRUE;
300 /* shader bytecode buffer manipulation functions.
301 * allocate_buffer creates a new buffer structure, put_dword adds a new
302 * DWORD to the buffer. In the rare case of a memory allocation failure
303 * when trying to grow the buffer a flag is set in the buffer to mark it
304 * invalid. This avoids return value checking and passing in many places
306 static struct bytecode_buffer *allocate_buffer(void) {
307 struct bytecode_buffer *ret;
309 ret = asm_alloc(sizeof(*ret));
310 if(!ret) return NULL;
312 ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
313 ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
314 if(!ret->data) {
315 asm_free(ret);
316 return NULL;
318 ret->state = S_OK;
319 return ret;
322 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
323 if(FAILED(buffer->state)) return;
325 if(buffer->alloc_size == buffer->size) {
326 DWORD *newarray;
327 buffer->alloc_size *= 2;
328 newarray = asm_realloc(buffer->data,
329 sizeof(DWORD) * buffer->alloc_size);
330 if(!newarray) {
331 ERR("Failed to grow the buffer data memory\n");
332 buffer->state = E_OUTOFMEMORY;
333 return;
335 buffer->data = newarray;
337 buffer->data[buffer->size++] = value;
340 /******************************************************
341 * Implementation of the writer functions starts here *
342 ******************************************************/
343 static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
344 const struct declaration *decls, unsigned int num, DWORD type) {
345 DWORD i;
346 DWORD instr_dcl = D3DSIO_DCL;
347 DWORD token;
349 if(len) {
350 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
353 for(i = 0; i < num; i++) {
354 /* Write the DCL instruction */
355 put_dword(buffer, instr_dcl);
357 /* Write the usage and index */
358 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
359 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
360 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
361 put_dword(buffer, token);
363 /* Write the dest register */
364 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
365 token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
366 token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL;
367 token |= decls[i].regnum & D3DSP_REGNUM_MASK;
368 token |= d3d9_dstmod(decls[i].mod);
369 put_dword(buffer, token);
373 static void write_const(struct constant **consts, int num, DWORD opcode, DWORD reg_type, struct bytecode_buffer *buffer, BOOL len) {
374 DWORD i;
375 DWORD instr_def = opcode;
376 const DWORD reg = (1<<31) |
377 ((reg_type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
378 ((reg_type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
379 D3DSP_WRITEMASK_ALL;
381 if(len) {
382 if(opcode == D3DSIO_DEFB)
383 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
384 else
385 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
388 for(i = 0; i < num; i++) {
389 /* Write the DEF instruction */
390 put_dword(buffer, instr_def);
392 put_dword(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
393 put_dword(buffer, consts[i]->value[0].d);
394 if(opcode != D3DSIO_DEFB) {
395 put_dword(buffer, consts[i]->value[1].d);
396 put_dword(buffer, consts[i]->value[2].d);
397 put_dword(buffer, consts[i]->value[3].d);
402 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
403 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
406 static HRESULT vs_find_builtin_varyings(struct bc_writer *This, const struct bwriter_shader *shader) {
407 DWORD i;
408 DWORD usage, usage_idx, writemask, regnum;
410 for(i = 0; i < shader->num_outputs; i++) {
411 usage = shader->outputs[i].usage;
412 usage_idx = shader->outputs[i].usage_idx;
413 writemask = shader->outputs[i].writemask;
414 regnum = shader->outputs[i].regnum;
416 switch(usage) {
417 case BWRITERDECLUSAGE_POSITION:
418 case BWRITERDECLUSAGE_POSITIONT:
419 if(usage_idx > 0) {
420 WARN("dcl_position%u not supported in sm 1/2 shaders\n", usage_idx);
421 return E_INVALIDARG;
423 TRACE("o%u is oPos\n", regnum);
424 This->oPos_regnum = regnum;
425 break;
427 case BWRITERDECLUSAGE_COLOR:
428 if(usage_idx > 1) {
429 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
430 return E_INVALIDARG;
432 if(writemask != BWRITERSP_WRITEMASK_ALL) {
433 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
434 return E_INVALIDARG;
436 TRACE("o%u is oD%u\n", regnum, usage_idx);
437 This->oD_regnum[usage_idx] = regnum;
438 break;
440 case BWRITERDECLUSAGE_TEXCOORD:
441 if(usage_idx >= 8) {
442 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
443 return E_INVALIDARG;
445 if(writemask != (BWRITERSP_WRITEMASK_0) &&
446 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
447 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
448 writemask != (BWRITERSP_WRITEMASK_ALL)) {
449 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
450 return E_INVALIDARG;
452 TRACE("o%u is oT%u\n", regnum, usage_idx);
453 This->oT_regnum[usage_idx] = regnum;
454 break;
456 case BWRITERDECLUSAGE_PSIZE:
457 if(usage_idx > 0) {
458 WARN("dcl_psize%u not supported in sm 1/2 shaders\n", usage_idx);
459 return E_INVALIDARG;
461 TRACE("o%u writemask 0x%08x is oPts\n", regnum, writemask);
462 This->oPts_regnum = regnum;
463 This->oPts_mask = writemask;
464 break;
466 case BWRITERDECLUSAGE_FOG:
467 if(usage_idx > 0) {
468 WARN("dcl_fog%u not supported in sm 1 shaders\n", usage_idx);
469 return E_INVALIDARG;
471 if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
472 writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
473 WARN("Unsupported fog writemask\n");
474 return E_INVALIDARG;
476 TRACE("o%u writemask 0x%08x is oFog\n", regnum, writemask);
477 This->oFog_regnum = regnum;
478 This->oFog_mask = writemask;
479 break;
481 default:
482 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
483 return E_INVALIDARG;
487 return S_OK;
490 static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
491 HRESULT hr;
493 if(shader->num_ci || shader->num_cb) {
494 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
495 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
496 This->state = E_INVALIDARG;
497 return;
500 hr = vs_find_builtin_varyings(This, shader);
501 if(FAILED(hr)) {
502 This->state = hr;
503 return;
506 /* Declare the shader type and version */
507 put_dword(buffer, This->version);
509 write_declarations(buffer, FALSE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
510 write_constF(shader, buffer, FALSE);
511 return;
514 static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
515 const struct bwriter_shader *shader,
516 DWORD texcoords) {
517 DWORD i;
518 DWORD usage, usage_idx, writemask, regnum;
520 This->v_regnum[0] = -1; This->v_regnum[1] = -1;
521 for(i = 0; i < 8; i++) This->t_regnum[i] = -1;
523 for(i = 0; i < shader->num_inputs; i++) {
524 usage = shader->inputs[i].usage;
525 usage_idx = shader->inputs[i].usage_idx;
526 writemask = shader->inputs[i].writemask;
527 regnum = shader->inputs[i].regnum;
529 switch(usage) {
530 case BWRITERDECLUSAGE_COLOR:
531 if(usage_idx > 1) {
532 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
533 return E_INVALIDARG;
535 if(writemask != BWRITERSP_WRITEMASK_ALL) {
536 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
537 return E_INVALIDARG;
539 TRACE("v%u is v%u\n", regnum, usage_idx);
540 This->v_regnum[usage_idx] = regnum;
541 break;
543 case BWRITERDECLUSAGE_TEXCOORD:
544 if(usage_idx > texcoords) {
545 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
546 return E_INVALIDARG;
548 if(writemask != (BWRITERSP_WRITEMASK_0) &&
549 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
550 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
551 writemask != (BWRITERSP_WRITEMASK_ALL)) {
552 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
553 } else {
554 writemask = BWRITERSP_WRITEMASK_ALL;
556 TRACE("v%u is t%u\n", regnum, usage_idx);
557 This->t_regnum[usage_idx] = regnum;
558 break;
560 default:
561 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
562 return E_INVALIDARG;
566 return S_OK;
569 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
570 put_dword(buffer, D3DSIO_END);
573 static DWORD map_vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
574 DWORD token = 0;
575 DWORD i;
577 *has_components = TRUE;
578 if(regnum == This->oPos_regnum) {
579 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
580 token |= D3DSRO_POSITION & D3DSP_REGNUM_MASK; /* No shift */
581 return token;
583 if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
584 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
585 token |= D3DSRO_FOG & D3DSP_REGNUM_MASK; /* No shift */
586 token |= D3DSP_WRITEMASK_ALL;
587 *has_components = FALSE;
588 return token;
590 if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
591 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
592 token |= D3DSRO_POINT_SIZE & D3DSP_REGNUM_MASK; /* No shift */
593 token |= D3DSP_WRITEMASK_ALL;
594 *has_components = FALSE;
595 return token;
597 for(i = 0; i < 2; i++) {
598 if(regnum == This->oD_regnum[i]) {
599 token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
600 token |= i & D3DSP_REGNUM_MASK; /* No shift */
601 return token;
604 for(i = 0; i < 8; i++) {
605 if(regnum == This->oT_regnum[i]) {
606 token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
607 token |= i & D3DSP_REGNUM_MASK; /* No shift */
608 return token;
612 /* The varying must be undeclared - if an unsupported varying was declared,
613 * the vs_find_builtin_varyings function would have caught it and this code
614 * would not run */
615 WARN("Undeclared varying %u\n", regnum);
616 This->state = E_INVALIDARG;
617 return -1;
620 static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
621 struct bytecode_buffer *buffer,
622 DWORD shift, DWORD mod) {
623 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
624 DWORD has_wmask;
626 if(reg->rel_reg) {
627 WARN("Relative addressing not supported for destination registers\n");
628 This->state = E_INVALIDARG;
629 return;
632 switch(reg->type) {
633 case BWRITERSPR_OUTPUT:
634 token |= map_vs_output(This, reg->regnum, reg->writemask, &has_wmask);
635 break;
637 case BWRITERSPR_RASTOUT:
638 case BWRITERSPR_ATTROUT:
639 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
640 * but are unexpected. If we hit this path it might be due to an error.
642 FIXME("Unexpected register type %u\n", reg->type);
643 /* drop through */
644 case BWRITERSPR_INPUT:
645 case BWRITERSPR_TEMP:
646 case BWRITERSPR_CONST:
647 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
648 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
649 has_wmask = TRUE;
650 break;
652 case BWRITERSPR_ADDR:
653 if(reg->regnum != 0) {
654 WARN("Only a0 exists\n");
655 This->state = E_INVALIDARG;
656 return;
658 token |= (D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
659 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
660 has_wmask = TRUE;
661 break;
663 case BWRITERSPR_PREDICATE:
664 if(This->version != BWRITERVS_VERSION(2, 1)){
665 WARN("Predicate register is allowed only in vs_2_x\n");
666 This->state = E_INVALIDARG;
667 return;
669 if(reg->regnum != 0) {
670 WARN("Only predicate register p0 exists\n");
671 This->state = E_INVALIDARG;
672 return;
674 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
675 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
676 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
677 has_wmask = TRUE;
678 break;
680 default:
681 WARN("Invalid register type for 1.x-2.x vertex shader\n");
682 This->state = E_INVALIDARG;
683 return;
686 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
687 * into the bytecode and since the compiler doesn't do such checks write them
688 * (the checks are done by the undocumented shader validator)
690 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
691 token |= d3d9_dstmod(mod);
693 if(has_wmask) {
694 token |= d3d9_writemask(reg->writemask);
696 put_dword(buffer, token);
699 static void vs_1_x_srcreg(struct bc_writer *This, const struct shader_reg *reg,
700 struct bytecode_buffer *buffer) {
701 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
702 DWORD has_swizzle;
703 DWORD component;
705 switch(reg->type) {
706 case BWRITERSPR_OUTPUT:
707 /* Map the swizzle to a writemask, the format expected
708 by map_vs_output
710 switch(reg->swizzle) {
711 case BWRITERVS_SWIZZLE_X:
712 component = BWRITERSP_WRITEMASK_0;
713 break;
714 case BWRITERVS_SWIZZLE_Y:
715 component = BWRITERSP_WRITEMASK_1;
716 break;
717 case BWRITERVS_SWIZZLE_Z:
718 component = BWRITERSP_WRITEMASK_2;
719 break;
720 case BWRITERVS_SWIZZLE_W:
721 component = BWRITERSP_WRITEMASK_3;
722 break;
723 default:
724 component = 0;
726 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
727 break;
729 case BWRITERSPR_RASTOUT:
730 case BWRITERSPR_ATTROUT:
731 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
732 * but are unexpected. If we hit this path it might be due to an error.
734 FIXME("Unexpected register type %u\n", reg->type);
735 /* drop through */
736 case BWRITERSPR_INPUT:
737 case BWRITERSPR_TEMP:
738 case BWRITERSPR_CONST:
739 case BWRITERSPR_ADDR:
740 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
741 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
742 if(reg->rel_reg) {
743 if(reg->rel_reg->type != BWRITERSPR_ADDR ||
744 reg->rel_reg->regnum != 0 ||
745 reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X) {
746 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
747 This->state = E_INVALIDARG;
748 return;
750 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
752 break;
754 default:
755 WARN("Invalid register type for 1.x vshader\n");
756 This->state = E_INVALIDARG;
757 return;
760 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
762 token |= d3d9_srcmod(reg->srcmod);
763 put_dword(buffer, token);
766 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
767 struct bytecode_buffer *buffer){
768 unsigned int i;
769 if(instr->has_predicate){
770 This->funcs->srcreg(This, &instr->predicate, buffer);
772 for(i = 0; i < instr->num_srcs; i++){
773 This->funcs->srcreg(This, &instr->src[i], buffer);
777 static DWORD map_ps_input(struct bc_writer *This,
778 const struct shader_reg *reg) {
779 DWORD i, token = 0;
780 /* Map color interpolators */
781 for(i = 0; i < 2; i++) {
782 if(reg->regnum == This->v_regnum[i]) {
783 token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
784 token |= i & D3DSP_REGNUM_MASK; /* No shift */
785 return token;
788 for(i = 0; i < 8; i++) {
789 if(reg->regnum == This->t_regnum[i]) {
790 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
791 token |= i & D3DSP_REGNUM_MASK; /* No shift */
792 return token;
796 WARN("Invalid ps 1/2 varying\n");
797 This->state = E_INVALIDARG;
798 return token;
801 /* The length of an instruction consists of the destination register (if any),
802 * the number of source registers, the number of address registers used for
803 * indirect addressing, and optionally the predicate register
805 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
806 unsigned int i;
807 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
809 if(dsts){
810 if(instr->dst.rel_reg) ret++;
812 for(i = 0; i < srcs; i++) {
813 if(instr->src[i].rel_reg) ret++;
815 return ret;
818 static void sm_1_x_opcode(struct bc_writer *This,
819 const struct instruction *instr,
820 DWORD token, struct bytecode_buffer *buffer) {
821 /* In sm_1_x instruction length isn't encoded */
822 if(instr->coissue){
823 token |= D3DSI_COISSUE;
825 put_dword(buffer, token);
828 static void instr_handler(struct bc_writer *This,
829 const struct instruction *instr,
830 struct bytecode_buffer *buffer) {
831 DWORD token = d3d9_opcode(instr->opcode);
832 TRACE("token: %x\n", token);
834 This->funcs->opcode(This, instr, token, buffer);
835 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
836 write_srcregs(This, instr, buffer);
839 static const struct instr_handler_table vs_1_x_handlers[] = {
840 {BWRITERSIO_ADD, instr_handler},
841 {BWRITERSIO_NOP, instr_handler},
842 {BWRITERSIO_MOV, instr_handler},
843 {BWRITERSIO_SUB, instr_handler},
844 {BWRITERSIO_MAD, instr_handler},
845 {BWRITERSIO_MUL, instr_handler},
846 {BWRITERSIO_RCP, instr_handler},
847 {BWRITERSIO_RSQ, instr_handler},
848 {BWRITERSIO_DP3, instr_handler},
849 {BWRITERSIO_DP4, instr_handler},
850 {BWRITERSIO_MIN, instr_handler},
851 {BWRITERSIO_MAX, instr_handler},
852 {BWRITERSIO_SLT, instr_handler},
853 {BWRITERSIO_SGE, instr_handler},
854 {BWRITERSIO_EXP, instr_handler},
855 {BWRITERSIO_LOG, instr_handler},
856 {BWRITERSIO_EXPP, instr_handler},
857 {BWRITERSIO_LOGP, instr_handler},
858 {BWRITERSIO_DST, instr_handler},
859 {BWRITERSIO_FRC, instr_handler},
860 {BWRITERSIO_M4x4, instr_handler},
861 {BWRITERSIO_M4x3, instr_handler},
862 {BWRITERSIO_M3x4, instr_handler},
863 {BWRITERSIO_M3x3, instr_handler},
864 {BWRITERSIO_M3x2, instr_handler},
865 {BWRITERSIO_LIT, instr_handler},
867 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
868 the end of the list */
871 static const struct bytecode_backend vs_1_x_backend = {
872 vs_1_x_header,
873 end,
874 vs_1_x_srcreg,
875 vs_12_dstreg,
876 sm_1_x_opcode,
877 vs_1_x_handlers
880 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
881 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
884 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
885 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
888 static void vs_2_header(struct bc_writer *This,
889 const struct bwriter_shader *shader,
890 struct bytecode_buffer *buffer) {
891 HRESULT hr;
893 hr = vs_find_builtin_varyings(This, shader);
894 if(FAILED(hr)) {
895 This->state = hr;
896 return;
899 /* Declare the shader type and version */
900 put_dword(buffer, This->version);
902 write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
903 write_constF(shader, buffer, TRUE);
904 write_constB(shader, buffer, TRUE);
905 write_constI(shader, buffer, TRUE);
906 return;
909 static void vs_2_srcreg(struct bc_writer *This,
910 const struct shader_reg *reg,
911 struct bytecode_buffer *buffer) {
912 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
913 DWORD has_swizzle;
914 DWORD component;
915 DWORD d3d9reg;
917 switch(reg->type) {
918 case BWRITERSPR_OUTPUT:
919 /* Map the swizzle to a writemask, the format expected
920 by map_vs_output
922 switch(reg->swizzle) {
923 case BWRITERVS_SWIZZLE_X:
924 component = BWRITERSP_WRITEMASK_0;
925 break;
926 case BWRITERVS_SWIZZLE_Y:
927 component = BWRITERSP_WRITEMASK_1;
928 break;
929 case BWRITERVS_SWIZZLE_Z:
930 component = BWRITERSP_WRITEMASK_2;
931 break;
932 case BWRITERVS_SWIZZLE_W:
933 component = BWRITERSP_WRITEMASK_3;
934 break;
935 default:
936 component = 0;
938 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
939 break;
941 case BWRITERSPR_RASTOUT:
942 case BWRITERSPR_ATTROUT:
943 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
944 * but are unexpected. If we hit this path it might be due to an error.
946 FIXME("Unexpected register type %u\n", reg->type);
947 /* drop through */
948 case BWRITERSPR_INPUT:
949 case BWRITERSPR_TEMP:
950 case BWRITERSPR_CONST:
951 case BWRITERSPR_ADDR:
952 case BWRITERSPR_CONSTINT:
953 case BWRITERSPR_CONSTBOOL:
954 case BWRITERSPR_LABEL:
955 d3d9reg = d3d9_register(reg->type);
956 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
957 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
958 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
959 break;
961 case BWRITERSPR_LOOP:
962 if(reg->regnum != 0) {
963 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
964 This->state = E_INVALIDARG;
965 return;
967 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
968 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
969 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
970 break;
972 case BWRITERSPR_PREDICATE:
973 if(This->version != BWRITERVS_VERSION(2, 1)){
974 WARN("Predicate register is allowed only in vs_2_x\n");
975 This->state = E_INVALIDARG;
976 return;
978 if(reg->regnum > 0) {
979 WARN("Only predicate register 0 is supported\n");
980 This->state = E_INVALIDARG;
981 return;
983 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
984 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
985 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
987 break;
989 default:
990 WARN("Invalid register type for 2.0 vshader\n");
991 This->state = E_INVALIDARG;
992 return;
995 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
997 token |= d3d9_srcmod(reg->srcmod);
999 if(reg->rel_reg)
1000 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1002 put_dword(buffer, token);
1004 /* vs_2_0 and newer write the register containing the index explicitly in the
1005 * binary code
1007 if(token & D3DVS_ADDRMODE_RELATIVE)
1008 vs_2_srcreg(This, reg->rel_reg, buffer);
1011 static void sm_2_opcode(struct bc_writer *This,
1012 const struct instruction *instr,
1013 DWORD token, struct bytecode_buffer *buffer) {
1014 /* From sm 2 onwards instruction length is encoded in the opcode field */
1015 int dsts = instr->has_dst ? 1 : 0;
1016 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
1017 if(instr->comptype)
1018 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1019 if(instr->has_predicate)
1020 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1021 put_dword(buffer,token);
1024 static const struct instr_handler_table vs_2_0_handlers[] = {
1025 {BWRITERSIO_ADD, instr_handler},
1026 {BWRITERSIO_NOP, instr_handler},
1027 {BWRITERSIO_MOV, instr_handler},
1028 {BWRITERSIO_SUB, instr_handler},
1029 {BWRITERSIO_MAD, instr_handler},
1030 {BWRITERSIO_MUL, instr_handler},
1031 {BWRITERSIO_RCP, instr_handler},
1032 {BWRITERSIO_RSQ, instr_handler},
1033 {BWRITERSIO_DP3, instr_handler},
1034 {BWRITERSIO_DP4, instr_handler},
1035 {BWRITERSIO_MIN, instr_handler},
1036 {BWRITERSIO_MAX, instr_handler},
1037 {BWRITERSIO_SLT, instr_handler},
1038 {BWRITERSIO_SGE, instr_handler},
1039 {BWRITERSIO_ABS, instr_handler},
1040 {BWRITERSIO_EXP, instr_handler},
1041 {BWRITERSIO_LOG, instr_handler},
1042 {BWRITERSIO_EXPP, instr_handler},
1043 {BWRITERSIO_LOGP, instr_handler},
1044 {BWRITERSIO_DST, instr_handler},
1045 {BWRITERSIO_LRP, instr_handler},
1046 {BWRITERSIO_FRC, instr_handler},
1047 {BWRITERSIO_CRS, instr_handler},
1048 {BWRITERSIO_SGN, instr_handler},
1049 {BWRITERSIO_NRM, instr_handler},
1050 {BWRITERSIO_SINCOS, instr_handler},
1051 {BWRITERSIO_M4x4, instr_handler},
1052 {BWRITERSIO_M4x3, instr_handler},
1053 {BWRITERSIO_M3x4, instr_handler},
1054 {BWRITERSIO_M3x3, instr_handler},
1055 {BWRITERSIO_M3x2, instr_handler},
1056 {BWRITERSIO_LIT, instr_handler},
1057 {BWRITERSIO_POW, instr_handler},
1058 {BWRITERSIO_MOVA, instr_handler},
1060 {BWRITERSIO_CALL, instr_handler},
1061 {BWRITERSIO_CALLNZ, instr_handler},
1062 {BWRITERSIO_REP, instr_handler},
1063 {BWRITERSIO_ENDREP, instr_handler},
1064 {BWRITERSIO_IF, instr_handler},
1065 {BWRITERSIO_LABEL, instr_handler},
1066 {BWRITERSIO_ELSE, instr_handler},
1067 {BWRITERSIO_ENDIF, instr_handler},
1068 {BWRITERSIO_LOOP, instr_handler},
1069 {BWRITERSIO_RET, instr_handler},
1070 {BWRITERSIO_ENDLOOP, instr_handler},
1072 {BWRITERSIO_END, NULL},
1075 static const struct bytecode_backend vs_2_0_backend = {
1076 vs_2_header,
1077 end,
1078 vs_2_srcreg,
1079 vs_12_dstreg,
1080 sm_2_opcode,
1081 vs_2_0_handlers
1084 static const struct instr_handler_table vs_2_x_handlers[] = {
1085 {BWRITERSIO_ADD, instr_handler},
1086 {BWRITERSIO_NOP, instr_handler},
1087 {BWRITERSIO_MOV, instr_handler},
1088 {BWRITERSIO_SUB, instr_handler},
1089 {BWRITERSIO_MAD, instr_handler},
1090 {BWRITERSIO_MUL, instr_handler},
1091 {BWRITERSIO_RCP, instr_handler},
1092 {BWRITERSIO_RSQ, instr_handler},
1093 {BWRITERSIO_DP3, instr_handler},
1094 {BWRITERSIO_DP4, instr_handler},
1095 {BWRITERSIO_MIN, instr_handler},
1096 {BWRITERSIO_MAX, instr_handler},
1097 {BWRITERSIO_SLT, instr_handler},
1098 {BWRITERSIO_SGE, instr_handler},
1099 {BWRITERSIO_ABS, instr_handler},
1100 {BWRITERSIO_EXP, instr_handler},
1101 {BWRITERSIO_LOG, instr_handler},
1102 {BWRITERSIO_EXPP, instr_handler},
1103 {BWRITERSIO_LOGP, instr_handler},
1104 {BWRITERSIO_DST, instr_handler},
1105 {BWRITERSIO_LRP, instr_handler},
1106 {BWRITERSIO_FRC, instr_handler},
1107 {BWRITERSIO_CRS, instr_handler},
1108 {BWRITERSIO_SGN, instr_handler},
1109 {BWRITERSIO_NRM, instr_handler},
1110 {BWRITERSIO_SINCOS, instr_handler},
1111 {BWRITERSIO_M4x4, instr_handler},
1112 {BWRITERSIO_M4x3, instr_handler},
1113 {BWRITERSIO_M3x4, instr_handler},
1114 {BWRITERSIO_M3x3, instr_handler},
1115 {BWRITERSIO_M3x2, instr_handler},
1116 {BWRITERSIO_LIT, instr_handler},
1117 {BWRITERSIO_POW, instr_handler},
1118 {BWRITERSIO_MOVA, instr_handler},
1120 {BWRITERSIO_CALL, instr_handler},
1121 {BWRITERSIO_CALLNZ, instr_handler},
1122 {BWRITERSIO_REP, instr_handler},
1123 {BWRITERSIO_ENDREP, instr_handler},
1124 {BWRITERSIO_IF, instr_handler},
1125 {BWRITERSIO_LABEL, instr_handler},
1126 {BWRITERSIO_IFC, instr_handler},
1127 {BWRITERSIO_ELSE, instr_handler},
1128 {BWRITERSIO_ENDIF, instr_handler},
1129 {BWRITERSIO_BREAK, instr_handler},
1130 {BWRITERSIO_BREAKC, instr_handler},
1131 {BWRITERSIO_LOOP, instr_handler},
1132 {BWRITERSIO_RET, instr_handler},
1133 {BWRITERSIO_ENDLOOP, instr_handler},
1135 {BWRITERSIO_SETP, instr_handler},
1136 {BWRITERSIO_BREAKP, instr_handler},
1138 {BWRITERSIO_END, NULL},
1141 static const struct bytecode_backend vs_2_x_backend = {
1142 vs_2_header,
1143 end,
1144 vs_2_srcreg,
1145 vs_12_dstreg,
1146 sm_2_opcode,
1147 vs_2_x_handlers
1150 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1151 DWORD i;
1152 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1153 DWORD token;
1154 const DWORD reg = (1<<31) |
1155 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
1156 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
1157 D3DSP_WRITEMASK_ALL;
1159 for(i = 0; i < shader->num_samplers; i++) {
1160 /* Write the DCL instruction */
1161 put_dword(buffer, instr_dcl);
1162 token = (1<<31);
1163 /* Already shifted */
1164 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
1165 put_dword(buffer, token);
1166 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1167 token |= d3d9_dstmod(shader->samplers[i].mod);
1168 put_dword(buffer, token);
1172 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1173 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1174 if(FAILED(hr)) {
1175 This->state = hr;
1176 return;
1179 /* Declare the shader type and version */
1180 put_dword(buffer, This->version);
1181 write_samplers(shader, buffer);
1182 write_constF(shader, buffer, TRUE);
1183 write_constB(shader, buffer, TRUE);
1184 write_constI(shader, buffer, TRUE);
1187 static void ps_2_srcreg(struct bc_writer *This,
1188 const struct shader_reg *reg,
1189 struct bytecode_buffer *buffer) {
1190 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1191 DWORD d3d9reg;
1192 if(reg->rel_reg) {
1193 WARN("Relative addressing not supported in <= ps_3_0\n");
1194 This->state = E_INVALIDARG;
1195 return;
1198 switch(reg->type) {
1199 case BWRITERSPR_INPUT:
1200 token |= map_ps_input(This, reg);
1201 break;
1203 /* Can be mapped 1:1 */
1204 case BWRITERSPR_TEMP:
1205 case BWRITERSPR_CONST:
1206 case BWRITERSPR_COLOROUT:
1207 case BWRITERSPR_CONSTBOOL:
1208 case BWRITERSPR_CONSTINT:
1209 case BWRITERSPR_SAMPLER:
1210 case BWRITERSPR_LABEL:
1211 case BWRITERSPR_DEPTHOUT:
1212 d3d9reg = d3d9_register(reg->type);
1213 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1214 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1215 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1216 break;
1218 case BWRITERSPR_PREDICATE:
1219 if(This->version != BWRITERPS_VERSION(2, 1)){
1220 WARN("Predicate register not supported in ps_2_0\n");
1221 This->state = E_INVALIDARG;
1223 if(reg->regnum) {
1224 WARN("Predicate register with regnum %u not supported\n",
1225 reg->regnum);
1226 This->state = E_INVALIDARG;
1228 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1229 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1230 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1231 break;
1233 default:
1234 WARN("Invalid register type for ps_2_0 shader\n");
1235 This->state = E_INVALIDARG;
1236 return;
1239 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1241 token |= d3d9_srcmod(reg->srcmod);
1242 put_dword(buffer, token);
1245 static void ps_2_0_dstreg(struct bc_writer *This,
1246 const struct shader_reg *reg,
1247 struct bytecode_buffer *buffer,
1248 DWORD shift, DWORD mod) {
1249 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1250 DWORD d3d9reg;
1252 if(reg->rel_reg) {
1253 WARN("Relative addressing not supported for destination registers\n");
1254 This->state = E_INVALIDARG;
1255 return;
1258 switch(reg->type) {
1259 case BWRITERSPR_TEMP: /* 1:1 mapping */
1260 case BWRITERSPR_COLOROUT:
1261 case BWRITERSPR_DEPTHOUT:
1262 d3d9reg = d3d9_register(reg->type);
1263 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1264 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1265 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1266 break;
1268 case BWRITERSPR_PREDICATE:
1269 if(This->version != BWRITERPS_VERSION(2, 1)){
1270 WARN("Predicate register not supported in ps_2_0\n");
1271 This->state = E_INVALIDARG;
1273 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1274 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1275 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1276 break;
1278 /* texkill uses the input register as a destination parameter */
1279 case BWRITERSPR_INPUT:
1280 token |= map_ps_input(This, reg);
1281 break;
1283 default:
1284 WARN("Invalid dest register type for 2.x pshader\n");
1285 This->state = E_INVALIDARG;
1286 return;
1289 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1290 token |= d3d9_dstmod(mod);
1292 token |= d3d9_writemask(reg->writemask);
1293 put_dword(buffer, token);
1296 static const struct instr_handler_table ps_2_0_handlers[] = {
1297 {BWRITERSIO_ADD, instr_handler},
1298 {BWRITERSIO_NOP, instr_handler},
1299 {BWRITERSIO_MOV, instr_handler},
1300 {BWRITERSIO_SUB, instr_handler},
1301 {BWRITERSIO_MAD, instr_handler},
1302 {BWRITERSIO_MUL, instr_handler},
1303 {BWRITERSIO_RCP, instr_handler},
1304 {BWRITERSIO_RSQ, instr_handler},
1305 {BWRITERSIO_DP3, instr_handler},
1306 {BWRITERSIO_DP4, instr_handler},
1307 {BWRITERSIO_MIN, instr_handler},
1308 {BWRITERSIO_MAX, instr_handler},
1309 {BWRITERSIO_ABS, instr_handler},
1310 {BWRITERSIO_EXP, instr_handler},
1311 {BWRITERSIO_LOG, instr_handler},
1312 {BWRITERSIO_EXPP, instr_handler},
1313 {BWRITERSIO_LOGP, instr_handler},
1314 {BWRITERSIO_LRP, instr_handler},
1315 {BWRITERSIO_FRC, instr_handler},
1316 {BWRITERSIO_CRS, instr_handler},
1317 {BWRITERSIO_NRM, instr_handler},
1318 {BWRITERSIO_SINCOS, instr_handler},
1319 {BWRITERSIO_M4x4, instr_handler},
1320 {BWRITERSIO_M4x3, instr_handler},
1321 {BWRITERSIO_M3x4, instr_handler},
1322 {BWRITERSIO_M3x3, instr_handler},
1323 {BWRITERSIO_M3x2, instr_handler},
1324 {BWRITERSIO_POW, instr_handler},
1325 {BWRITERSIO_DP2ADD, instr_handler},
1326 {BWRITERSIO_CMP, instr_handler},
1328 {BWRITERSIO_TEX, instr_handler},
1329 {BWRITERSIO_TEXLDP, instr_handler},
1330 {BWRITERSIO_TEXLDB, instr_handler},
1331 {BWRITERSIO_TEXKILL, instr_handler},
1333 {BWRITERSIO_END, NULL},
1336 static const struct bytecode_backend ps_2_0_backend = {
1337 ps_2_header,
1338 end,
1339 ps_2_srcreg,
1340 ps_2_0_dstreg,
1341 sm_2_opcode,
1342 ps_2_0_handlers
1345 static const struct instr_handler_table ps_2_x_handlers[] = {
1346 {BWRITERSIO_ADD, instr_handler},
1347 {BWRITERSIO_NOP, instr_handler},
1348 {BWRITERSIO_MOV, instr_handler},
1349 {BWRITERSIO_SUB, instr_handler},
1350 {BWRITERSIO_MAD, instr_handler},
1351 {BWRITERSIO_MUL, instr_handler},
1352 {BWRITERSIO_RCP, instr_handler},
1353 {BWRITERSIO_RSQ, instr_handler},
1354 {BWRITERSIO_DP3, instr_handler},
1355 {BWRITERSIO_DP4, instr_handler},
1356 {BWRITERSIO_MIN, instr_handler},
1357 {BWRITERSIO_MAX, instr_handler},
1358 {BWRITERSIO_ABS, instr_handler},
1359 {BWRITERSIO_EXP, instr_handler},
1360 {BWRITERSIO_LOG, instr_handler},
1361 {BWRITERSIO_EXPP, instr_handler},
1362 {BWRITERSIO_LOGP, instr_handler},
1363 {BWRITERSIO_LRP, instr_handler},
1364 {BWRITERSIO_FRC, instr_handler},
1365 {BWRITERSIO_CRS, instr_handler},
1366 {BWRITERSIO_NRM, instr_handler},
1367 {BWRITERSIO_SINCOS, instr_handler},
1368 {BWRITERSIO_M4x4, instr_handler},
1369 {BWRITERSIO_M4x3, instr_handler},
1370 {BWRITERSIO_M3x4, instr_handler},
1371 {BWRITERSIO_M3x3, instr_handler},
1372 {BWRITERSIO_M3x2, instr_handler},
1373 {BWRITERSIO_POW, instr_handler},
1374 {BWRITERSIO_DP2ADD, instr_handler},
1375 {BWRITERSIO_CMP, instr_handler},
1377 {BWRITERSIO_CALL, instr_handler},
1378 {BWRITERSIO_CALLNZ, instr_handler},
1379 {BWRITERSIO_REP, instr_handler},
1380 {BWRITERSIO_ENDREP, instr_handler},
1381 {BWRITERSIO_IF, instr_handler},
1382 {BWRITERSIO_LABEL, instr_handler},
1383 {BWRITERSIO_IFC, instr_handler},
1384 {BWRITERSIO_ELSE, instr_handler},
1385 {BWRITERSIO_ENDIF, instr_handler},
1386 {BWRITERSIO_BREAK, instr_handler},
1387 {BWRITERSIO_BREAKC, instr_handler},
1388 {BWRITERSIO_RET, instr_handler},
1390 {BWRITERSIO_TEX, instr_handler},
1391 {BWRITERSIO_TEXLDP, instr_handler},
1392 {BWRITERSIO_TEXLDB, instr_handler},
1393 {BWRITERSIO_TEXKILL, instr_handler},
1394 {BWRITERSIO_DSX, instr_handler},
1395 {BWRITERSIO_DSY, instr_handler},
1397 {BWRITERSIO_SETP, instr_handler},
1398 {BWRITERSIO_BREAKP, instr_handler},
1400 {BWRITERSIO_TEXLDD, instr_handler},
1402 {BWRITERSIO_END, NULL},
1405 static const struct bytecode_backend ps_2_x_backend = {
1406 ps_2_header,
1407 end,
1408 ps_2_srcreg,
1409 ps_2_0_dstreg,
1410 sm_2_opcode,
1411 ps_2_x_handlers
1414 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1415 /* Declare the shader type and version */
1416 put_dword(buffer, This->version);
1418 write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
1419 write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT);
1420 write_constF(shader, buffer, TRUE);
1421 write_constB(shader, buffer, TRUE);
1422 write_constI(shader, buffer, TRUE);
1423 write_samplers(shader, buffer);
1424 return;
1427 static void sm_3_srcreg(struct bc_writer *This,
1428 const struct shader_reg *reg,
1429 struct bytecode_buffer *buffer) {
1430 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1431 DWORD d3d9reg;
1433 d3d9reg = d3d9_register(reg->type);
1434 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1435 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1436 token |= reg->regnum & D3DSP_REGNUM_MASK;
1438 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
1439 token |= d3d9_srcmod(reg->srcmod);
1441 if(reg->rel_reg) {
1442 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
1443 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
1444 This->state = E_INVALIDARG;
1445 return;
1447 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
1448 reg->rel_reg->type == BWRITERSPR_LOOP) &&
1449 reg->rel_reg->regnum == 0) {
1450 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1451 } else {
1452 WARN("Unsupported relative addressing register\n");
1453 This->state = E_INVALIDARG;
1454 return;
1458 put_dword(buffer, token);
1460 /* vs_2_0 and newer write the register containing the index explicitly in the
1461 * binary code
1463 if(token & D3DVS_ADDRMODE_RELATIVE) {
1464 sm_3_srcreg(This, reg->rel_reg, buffer);
1468 static void sm_3_dstreg(struct bc_writer *This,
1469 const struct shader_reg *reg,
1470 struct bytecode_buffer *buffer,
1471 DWORD shift, DWORD mod) {
1472 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1473 DWORD d3d9reg;
1475 if(reg->rel_reg) {
1476 if(This->version == BWRITERVS_VERSION(3, 0) &&
1477 reg->type == BWRITERSPR_OUTPUT) {
1478 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1479 } else {
1480 WARN("Relative addressing not supported for this shader type or register type\n");
1481 This->state = E_INVALIDARG;
1482 return;
1486 d3d9reg = d3d9_register(reg->type);
1487 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1488 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1489 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1491 token |= d3d9_dstmod(mod);
1493 token |= d3d9_writemask(reg->writemask);
1494 put_dword(buffer, token);
1496 /* vs_2_0 and newer write the register containing the index explicitly in the
1497 * binary code
1499 if(token & D3DVS_ADDRMODE_RELATIVE) {
1500 sm_3_srcreg(This, reg->rel_reg, buffer);
1504 static const struct instr_handler_table vs_3_handlers[] = {
1505 {BWRITERSIO_ADD, instr_handler},
1506 {BWRITERSIO_NOP, instr_handler},
1507 {BWRITERSIO_MOV, instr_handler},
1508 {BWRITERSIO_SUB, instr_handler},
1509 {BWRITERSIO_MAD, instr_handler},
1510 {BWRITERSIO_MUL, instr_handler},
1511 {BWRITERSIO_RCP, instr_handler},
1512 {BWRITERSIO_RSQ, instr_handler},
1513 {BWRITERSIO_DP3, instr_handler},
1514 {BWRITERSIO_DP4, instr_handler},
1515 {BWRITERSIO_MIN, instr_handler},
1516 {BWRITERSIO_MAX, instr_handler},
1517 {BWRITERSIO_SLT, instr_handler},
1518 {BWRITERSIO_SGE, instr_handler},
1519 {BWRITERSIO_ABS, instr_handler},
1520 {BWRITERSIO_EXP, instr_handler},
1521 {BWRITERSIO_LOG, instr_handler},
1522 {BWRITERSIO_EXPP, instr_handler},
1523 {BWRITERSIO_LOGP, instr_handler},
1524 {BWRITERSIO_DST, instr_handler},
1525 {BWRITERSIO_LRP, instr_handler},
1526 {BWRITERSIO_FRC, instr_handler},
1527 {BWRITERSIO_CRS, instr_handler},
1528 {BWRITERSIO_SGN, instr_handler},
1529 {BWRITERSIO_NRM, instr_handler},
1530 {BWRITERSIO_SINCOS, instr_handler},
1531 {BWRITERSIO_M4x4, instr_handler},
1532 {BWRITERSIO_M4x3, instr_handler},
1533 {BWRITERSIO_M3x4, instr_handler},
1534 {BWRITERSIO_M3x3, instr_handler},
1535 {BWRITERSIO_M3x2, instr_handler},
1536 {BWRITERSIO_LIT, instr_handler},
1537 {BWRITERSIO_POW, instr_handler},
1538 {BWRITERSIO_MOVA, instr_handler},
1540 {BWRITERSIO_CALL, instr_handler},
1541 {BWRITERSIO_CALLNZ, instr_handler},
1542 {BWRITERSIO_REP, instr_handler},
1543 {BWRITERSIO_ENDREP, instr_handler},
1544 {BWRITERSIO_IF, instr_handler},
1545 {BWRITERSIO_LABEL, instr_handler},
1546 {BWRITERSIO_IFC, instr_handler},
1547 {BWRITERSIO_ELSE, instr_handler},
1548 {BWRITERSIO_ENDIF, instr_handler},
1549 {BWRITERSIO_BREAK, instr_handler},
1550 {BWRITERSIO_BREAKC, instr_handler},
1551 {BWRITERSIO_LOOP, instr_handler},
1552 {BWRITERSIO_RET, instr_handler},
1553 {BWRITERSIO_ENDLOOP, instr_handler},
1555 {BWRITERSIO_SETP, instr_handler},
1556 {BWRITERSIO_BREAKP, instr_handler},
1557 {BWRITERSIO_TEXLDL, instr_handler},
1559 {BWRITERSIO_END, NULL},
1562 static const struct bytecode_backend vs_3_backend = {
1563 sm_3_header,
1564 end,
1565 sm_3_srcreg,
1566 sm_3_dstreg,
1567 sm_2_opcode,
1568 vs_3_handlers
1571 static const struct instr_handler_table ps_3_handlers[] = {
1572 {BWRITERSIO_ADD, instr_handler},
1573 {BWRITERSIO_NOP, instr_handler},
1574 {BWRITERSIO_MOV, instr_handler},
1575 {BWRITERSIO_SUB, instr_handler},
1576 {BWRITERSIO_MAD, instr_handler},
1577 {BWRITERSIO_MUL, instr_handler},
1578 {BWRITERSIO_RCP, instr_handler},
1579 {BWRITERSIO_RSQ, instr_handler},
1580 {BWRITERSIO_DP3, instr_handler},
1581 {BWRITERSIO_DP4, instr_handler},
1582 {BWRITERSIO_MIN, instr_handler},
1583 {BWRITERSIO_MAX, instr_handler},
1584 {BWRITERSIO_ABS, instr_handler},
1585 {BWRITERSIO_EXP, instr_handler},
1586 {BWRITERSIO_LOG, instr_handler},
1587 {BWRITERSIO_EXPP, instr_handler},
1588 {BWRITERSIO_LOGP, instr_handler},
1589 {BWRITERSIO_LRP, instr_handler},
1590 {BWRITERSIO_FRC, instr_handler},
1591 {BWRITERSIO_CRS, instr_handler},
1592 {BWRITERSIO_NRM, instr_handler},
1593 {BWRITERSIO_SINCOS, instr_handler},
1594 {BWRITERSIO_M4x4, instr_handler},
1595 {BWRITERSIO_M4x3, instr_handler},
1596 {BWRITERSIO_M3x4, instr_handler},
1597 {BWRITERSIO_M3x3, instr_handler},
1598 {BWRITERSIO_M3x2, instr_handler},
1599 {BWRITERSIO_POW, instr_handler},
1600 {BWRITERSIO_DP2ADD, instr_handler},
1601 {BWRITERSIO_CMP, instr_handler},
1603 {BWRITERSIO_CALL, instr_handler},
1604 {BWRITERSIO_CALLNZ, instr_handler},
1605 {BWRITERSIO_REP, instr_handler},
1606 {BWRITERSIO_ENDREP, instr_handler},
1607 {BWRITERSIO_IF, instr_handler},
1608 {BWRITERSIO_LABEL, instr_handler},
1609 {BWRITERSIO_IFC, instr_handler},
1610 {BWRITERSIO_ELSE, instr_handler},
1611 {BWRITERSIO_ENDIF, instr_handler},
1612 {BWRITERSIO_BREAK, instr_handler},
1613 {BWRITERSIO_BREAKC, instr_handler},
1614 {BWRITERSIO_LOOP, instr_handler},
1615 {BWRITERSIO_RET, instr_handler},
1616 {BWRITERSIO_ENDLOOP, instr_handler},
1618 {BWRITERSIO_SETP, instr_handler},
1619 {BWRITERSIO_BREAKP, instr_handler},
1620 {BWRITERSIO_TEXLDL, instr_handler},
1622 {BWRITERSIO_TEX, instr_handler},
1623 {BWRITERSIO_TEXLDP, instr_handler},
1624 {BWRITERSIO_TEXLDB, instr_handler},
1625 {BWRITERSIO_TEXKILL, instr_handler},
1626 {BWRITERSIO_DSX, instr_handler},
1627 {BWRITERSIO_DSY, instr_handler},
1628 {BWRITERSIO_TEXLDD, instr_handler},
1630 {BWRITERSIO_END, NULL},
1633 static const struct bytecode_backend ps_3_backend = {
1634 sm_3_header,
1635 end,
1636 sm_3_srcreg,
1637 sm_3_dstreg,
1638 sm_2_opcode,
1639 ps_3_handlers
1642 static void init_vs10_dx9_writer(struct bc_writer *writer) {
1643 TRACE("Creating DirectX9 vertex shader 1.0 writer\n");
1644 writer->funcs = &vs_1_x_backend;
1647 static void init_vs11_dx9_writer(struct bc_writer *writer) {
1648 TRACE("Creating DirectX9 vertex shader 1.1 writer\n");
1649 writer->funcs = &vs_1_x_backend;
1652 static void init_vs20_dx9_writer(struct bc_writer *writer) {
1653 TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
1654 writer->funcs = &vs_2_0_backend;
1657 static void init_vs2x_dx9_writer(struct bc_writer *writer) {
1658 TRACE("Creating DirectX9 vertex shader 2.x writer\n");
1659 writer->funcs = &vs_2_x_backend;
1662 static void init_vs30_dx9_writer(struct bc_writer *writer) {
1663 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
1664 writer->funcs = &vs_3_backend;
1667 static void init_ps20_dx9_writer(struct bc_writer *writer) {
1668 TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
1669 writer->funcs = &ps_2_0_backend;
1672 static void init_ps2x_dx9_writer(struct bc_writer *writer) {
1673 TRACE("Creating DirectX9 pixel shader 2.x writer\n");
1674 writer->funcs = &ps_2_x_backend;
1677 static void init_ps30_dx9_writer(struct bc_writer *writer) {
1678 TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
1679 writer->funcs = &ps_3_backend;
1682 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
1683 struct bc_writer *ret = asm_alloc(sizeof(*ret));
1685 if(!ret) {
1686 WARN("Failed to allocate a bytecode writer instance\n");
1687 return NULL;
1690 switch(version) {
1691 case BWRITERVS_VERSION(1, 0):
1692 if(dxversion != 9) {
1693 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
1694 goto fail;
1696 init_vs10_dx9_writer(ret);
1697 break;
1698 case BWRITERVS_VERSION(1, 1):
1699 if(dxversion != 9) {
1700 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
1701 goto fail;
1703 init_vs11_dx9_writer(ret);
1704 break;
1705 case BWRITERVS_VERSION(2, 0):
1706 if(dxversion != 9) {
1707 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
1708 goto fail;
1710 init_vs20_dx9_writer(ret);
1711 break;
1712 case BWRITERVS_VERSION(2, 1):
1713 if(dxversion != 9) {
1714 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
1715 goto fail;
1717 init_vs2x_dx9_writer(ret);
1718 break;
1719 case BWRITERVS_VERSION(3, 0):
1720 if(dxversion != 9) {
1721 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
1722 goto fail;
1724 init_vs30_dx9_writer(ret);
1725 break;
1727 case BWRITERPS_VERSION(1, 0):
1728 if(dxversion != 9) {
1729 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
1730 goto fail;
1732 /* TODO: Set the appropriate writer backend */
1733 break;
1734 case BWRITERPS_VERSION(1, 1):
1735 if(dxversion != 9) {
1736 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
1737 goto fail;
1739 /* TODO: Set the appropriate writer backend */
1740 break;
1741 case BWRITERPS_VERSION(1, 2):
1742 if(dxversion != 9) {
1743 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
1744 goto fail;
1746 /* TODO: Set the appropriate writer backend */
1747 break;
1748 case BWRITERPS_VERSION(1, 3):
1749 if(dxversion != 9) {
1750 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
1751 goto fail;
1753 /* TODO: Set the appropriate writer backend */
1754 break;
1755 case BWRITERPS_VERSION(1, 4):
1756 if(dxversion != 9) {
1757 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
1758 goto fail;
1760 /* TODO: Set the appropriate writer backend */
1761 break;
1763 case BWRITERPS_VERSION(2, 0):
1764 if(dxversion != 9) {
1765 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
1766 goto fail;
1768 init_ps20_dx9_writer(ret);
1769 break;
1771 case BWRITERPS_VERSION(2, 1):
1772 if(dxversion != 9) {
1773 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
1774 goto fail;
1776 init_ps2x_dx9_writer(ret);
1777 break;
1779 case BWRITERPS_VERSION(3, 0):
1780 if(dxversion != 9) {
1781 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
1782 goto fail;
1784 init_ps30_dx9_writer(ret);
1785 break;
1787 default:
1788 WARN("Unexpected shader version requested: %08x\n", version);
1789 goto fail;
1791 ret->version = version;
1792 return ret;
1794 fail:
1795 asm_free(ret);
1796 return NULL;
1799 static HRESULT call_instr_handler(struct bc_writer *writer,
1800 const struct instruction *instr,
1801 struct bytecode_buffer *buffer) {
1802 DWORD i=0;
1804 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
1805 if(instr->opcode == writer->funcs->instructions[i].opcode) {
1806 if(!writer->funcs->instructions[i].func) {
1807 WARN("Opcode %u not supported by this profile\n", instr->opcode);
1808 return E_INVALIDARG;
1810 writer->funcs->instructions[i].func(writer, instr, buffer);
1811 return S_OK;
1813 i++;
1816 FIXME("Unhandled instruction %u\n", instr->opcode);
1817 return E_INVALIDARG;
1820 /* SlWriteBytecode (wineshader.@)
1822 * Writes shader version specific bytecode from the shader passed in.
1823 * The returned bytecode can be passed to the Direct3D runtime like
1824 * IDirect3DDevice9::Create*Shader.
1826 * Parameters:
1827 * shader: Shader to translate into bytecode
1828 * version: Shader version to generate(d3d version token)
1829 * dxversion: DirectX version the code targets
1830 * result: the resulting shader bytecode
1832 * Return values:
1833 * S_OK on success
1835 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
1836 struct bc_writer *writer;
1837 struct bytecode_buffer *buffer = NULL;
1838 HRESULT hr;
1839 unsigned int i;
1841 if(!shader){
1842 ERR("NULL shader structure, aborting\n");
1843 return E_FAIL;
1845 writer = create_writer(shader->version, dxversion);
1846 *result = NULL;
1848 if(!writer) {
1849 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
1850 WARN("or out of memory\n");
1851 hr = E_FAIL;
1852 goto error;
1855 buffer = allocate_buffer();
1856 if(!buffer) {
1857 WARN("Failed to allocate a buffer for the shader bytecode\n");
1858 hr = E_FAIL;
1859 goto error;
1862 writer->funcs->header(writer, shader, buffer);
1863 if(FAILED(writer->state)) {
1864 hr = writer->state;
1865 goto error;
1868 for(i = 0; i < shader->num_instrs; i++) {
1869 hr = call_instr_handler(writer, shader->instr[i], buffer);
1870 if(FAILED(hr)) {
1871 goto error;
1875 if(FAILED(writer->state)) {
1876 hr = writer->state;
1877 goto error;
1880 writer->funcs->end(writer, shader, buffer);
1882 if(FAILED(buffer->state)) {
1883 hr = buffer->state;
1884 goto error;
1887 /* Cut off unneeded memory from the result buffer */
1888 *result = asm_realloc(buffer->data,
1889 sizeof(DWORD) * buffer->size);
1890 if(!*result) {
1891 *result = buffer->data;
1893 buffer->data = NULL;
1894 hr = S_OK;
1896 error:
1897 if(buffer) {
1898 asm_free(buffer->data);
1899 asm_free(buffer);
1901 asm_free(writer);
1902 return hr;
1905 void SlDeleteShader(struct bwriter_shader *shader) {
1906 unsigned int i, j;
1908 TRACE("Deleting shader %p\n", shader);
1910 for(i = 0; i < shader->num_cf; i++) {
1911 asm_free(shader->constF[i]);
1913 asm_free(shader->constF);
1914 for(i = 0; i < shader->num_ci; i++) {
1915 asm_free(shader->constI[i]);
1917 asm_free(shader->constI);
1918 for(i = 0; i < shader->num_cb; i++) {
1919 asm_free(shader->constB[i]);
1921 asm_free(shader->constB);
1923 asm_free(shader->inputs);
1924 asm_free(shader->outputs);
1925 asm_free(shader->samplers);
1927 for(i = 0; i < shader->num_instrs; i++) {
1928 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
1929 asm_free(shader->instr[i]->src[j].rel_reg);
1931 asm_free(shader->instr[i]->src);
1932 asm_free(shader->instr[i]);
1934 asm_free(shader->instr);
1936 asm_free(shader);