cryptui: Add Norwegian Bokmål translation.
[wine/hacks.git] / dlls / d3dx9_36 / bytecodewriter.c
blobb444365452232d84f773a32d6198b3706d4f2a96
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 end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
582 put_dword(buffer, D3DSIO_END);
585 static DWORD map_vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
586 DWORD token = 0;
587 DWORD i;
589 *has_components = TRUE;
590 if(regnum == This->oPos_regnum) {
591 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
592 token |= D3DSRO_POSITION & D3DSP_REGNUM_MASK; /* No shift */
593 return token;
595 if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
596 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
597 token |= D3DSRO_FOG & D3DSP_REGNUM_MASK; /* No shift */
598 token |= D3DSP_WRITEMASK_ALL;
599 *has_components = FALSE;
600 return token;
602 if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
603 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
604 token |= D3DSRO_POINT_SIZE & D3DSP_REGNUM_MASK; /* No shift */
605 token |= D3DSP_WRITEMASK_ALL;
606 *has_components = FALSE;
607 return token;
609 for(i = 0; i < 2; i++) {
610 if(regnum == This->oD_regnum[i]) {
611 token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
612 token |= i & D3DSP_REGNUM_MASK; /* No shift */
613 return token;
616 for(i = 0; i < 8; i++) {
617 if(regnum == This->oT_regnum[i]) {
618 token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
619 token |= i & D3DSP_REGNUM_MASK; /* No shift */
620 return token;
624 /* The varying must be undeclared - if an unsupported varying was declared,
625 * the vs_find_builtin_varyings function would have caught it and this code
626 * would not run */
627 WARN("Undeclared varying %u\n", regnum);
628 This->state = E_INVALIDARG;
629 return -1;
632 static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
633 struct bytecode_buffer *buffer,
634 DWORD shift, DWORD mod) {
635 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
636 DWORD has_wmask;
638 if(reg->rel_reg) {
639 WARN("Relative addressing not supported for destination registers\n");
640 This->state = E_INVALIDARG;
641 return;
644 switch(reg->type) {
645 case BWRITERSPR_OUTPUT:
646 token |= map_vs_output(This, reg->regnum, reg->writemask, &has_wmask);
647 break;
649 case BWRITERSPR_RASTOUT:
650 case BWRITERSPR_ATTROUT:
651 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
652 * but are unexpected. If we hit this path it might be due to an error.
654 FIXME("Unexpected register type %u\n", reg->type);
655 /* drop through */
656 case BWRITERSPR_INPUT:
657 case BWRITERSPR_TEMP:
658 case BWRITERSPR_CONST:
659 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
660 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
661 has_wmask = TRUE;
662 break;
664 case BWRITERSPR_ADDR:
665 if(reg->regnum != 0) {
666 WARN("Only a0 exists\n");
667 This->state = E_INVALIDARG;
668 return;
670 token |= (D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
671 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
672 has_wmask = TRUE;
673 break;
675 case BWRITERSPR_PREDICATE:
676 if(This->version != BWRITERVS_VERSION(2, 1)){
677 WARN("Predicate register is allowed only in vs_2_x\n");
678 This->state = E_INVALIDARG;
679 return;
681 if(reg->regnum != 0) {
682 WARN("Only predicate register p0 exists\n");
683 This->state = E_INVALIDARG;
684 return;
686 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
687 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
688 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
689 has_wmask = TRUE;
690 break;
692 default:
693 WARN("Invalid register type for 1.x-2.x vertex shader\n");
694 This->state = E_INVALIDARG;
695 return;
698 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
699 * into the bytecode and since the compiler doesn't do such checks write them
700 * (the checks are done by the undocumented shader validator)
702 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
703 token |= d3d9_dstmod(mod);
705 if(has_wmask) {
706 token |= d3d9_writemask(reg->writemask);
708 put_dword(buffer, token);
711 static void vs_1_x_srcreg(struct bc_writer *This, const struct shader_reg *reg,
712 struct bytecode_buffer *buffer) {
713 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
714 DWORD has_swizzle;
715 DWORD component;
717 switch(reg->type) {
718 case BWRITERSPR_OUTPUT:
719 /* Map the swizzle to a writemask, the format expected
720 by map_vs_output
722 switch(reg->swizzle) {
723 case BWRITERVS_SWIZZLE_X:
724 component = BWRITERSP_WRITEMASK_0;
725 break;
726 case BWRITERVS_SWIZZLE_Y:
727 component = BWRITERSP_WRITEMASK_1;
728 break;
729 case BWRITERVS_SWIZZLE_Z:
730 component = BWRITERSP_WRITEMASK_2;
731 break;
732 case BWRITERVS_SWIZZLE_W:
733 component = BWRITERSP_WRITEMASK_3;
734 break;
735 default:
736 component = 0;
738 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
739 break;
741 case BWRITERSPR_RASTOUT:
742 case BWRITERSPR_ATTROUT:
743 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
744 * but are unexpected. If we hit this path it might be due to an error.
746 FIXME("Unexpected register type %u\n", reg->type);
747 /* drop through */
748 case BWRITERSPR_INPUT:
749 case BWRITERSPR_TEMP:
750 case BWRITERSPR_CONST:
751 case BWRITERSPR_ADDR:
752 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
753 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
754 if(reg->rel_reg) {
755 if(reg->rel_reg->type != BWRITERSPR_ADDR ||
756 reg->rel_reg->regnum != 0 ||
757 reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X) {
758 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
759 This->state = E_INVALIDARG;
760 return;
762 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
764 break;
766 default:
767 WARN("Invalid register type for 1.x vshader\n");
768 This->state = E_INVALIDARG;
769 return;
772 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
774 token |= d3d9_srcmod(reg->srcmod);
775 put_dword(buffer, token);
778 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
779 struct bytecode_buffer *buffer){
780 unsigned int i;
781 if(instr->has_predicate){
782 This->funcs->srcreg(This, &instr->predicate, buffer);
784 for(i = 0; i < instr->num_srcs; i++){
785 This->funcs->srcreg(This, &instr->src[i], buffer);
789 static DWORD map_ps_input(struct bc_writer *This,
790 const struct shader_reg *reg) {
791 DWORD i, token = 0;
792 /* Map color interpolators */
793 for(i = 0; i < 2; i++) {
794 if(reg->regnum == This->v_regnum[i]) {
795 token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
796 token |= i & D3DSP_REGNUM_MASK; /* No shift */
797 return token;
800 for(i = 0; i < 8; i++) {
801 if(reg->regnum == This->t_regnum[i]) {
802 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
803 token |= i & D3DSP_REGNUM_MASK; /* No shift */
804 return token;
808 WARN("Invalid ps 1/2 varying\n");
809 This->state = E_INVALIDARG;
810 return token;
813 /* The length of an instruction consists of the destination register (if any),
814 * the number of source registers, the number of address registers used for
815 * indirect addressing, and optionally the predicate register
817 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
818 unsigned int i;
819 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
821 if(dsts){
822 if(instr->dst.rel_reg) ret++;
824 for(i = 0; i < srcs; i++) {
825 if(instr->src[i].rel_reg) ret++;
827 return ret;
830 static void sm_1_x_opcode(struct bc_writer *This,
831 const struct instruction *instr,
832 DWORD token, struct bytecode_buffer *buffer) {
833 /* In sm_1_x instruction length isn't encoded */
834 if(instr->coissue){
835 token |= D3DSI_COISSUE;
837 put_dword(buffer, token);
840 static void instr_handler(struct bc_writer *This,
841 const struct instruction *instr,
842 struct bytecode_buffer *buffer) {
843 DWORD token = d3d9_opcode(instr->opcode);
845 This->funcs->opcode(This, instr, token, buffer);
846 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
847 write_srcregs(This, instr, buffer);
850 static const struct instr_handler_table vs_1_x_handlers[] = {
851 {BWRITERSIO_ADD, instr_handler},
852 {BWRITERSIO_NOP, instr_handler},
853 {BWRITERSIO_MOV, instr_handler},
854 {BWRITERSIO_SUB, instr_handler},
855 {BWRITERSIO_MAD, instr_handler},
856 {BWRITERSIO_MUL, instr_handler},
857 {BWRITERSIO_RCP, instr_handler},
858 {BWRITERSIO_RSQ, instr_handler},
859 {BWRITERSIO_DP3, instr_handler},
860 {BWRITERSIO_DP4, instr_handler},
861 {BWRITERSIO_MIN, instr_handler},
862 {BWRITERSIO_MAX, instr_handler},
863 {BWRITERSIO_SLT, instr_handler},
864 {BWRITERSIO_SGE, instr_handler},
865 {BWRITERSIO_EXP, instr_handler},
866 {BWRITERSIO_LOG, instr_handler},
867 {BWRITERSIO_EXPP, instr_handler},
868 {BWRITERSIO_LOGP, instr_handler},
869 {BWRITERSIO_DST, instr_handler},
870 {BWRITERSIO_FRC, instr_handler},
871 {BWRITERSIO_M4x4, instr_handler},
872 {BWRITERSIO_M4x3, instr_handler},
873 {BWRITERSIO_M3x4, instr_handler},
874 {BWRITERSIO_M3x3, instr_handler},
875 {BWRITERSIO_M3x2, instr_handler},
876 {BWRITERSIO_LIT, instr_handler},
878 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
879 the end of the list */
882 static const struct bytecode_backend vs_1_x_backend = {
883 vs_1_x_header,
884 end,
885 vs_1_x_srcreg,
886 vs_12_dstreg,
887 sm_1_x_opcode,
888 vs_1_x_handlers
891 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
892 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
895 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
896 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
899 static void vs_2_header(struct bc_writer *This,
900 const struct bwriter_shader *shader,
901 struct bytecode_buffer *buffer) {
902 HRESULT hr;
904 hr = vs_find_builtin_varyings(This, shader);
905 if(FAILED(hr)) {
906 This->state = hr;
907 return;
910 /* Declare the shader type and version */
911 put_dword(buffer, This->version);
913 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
914 write_constF(shader, buffer, TRUE);
915 write_constB(shader, buffer, TRUE);
916 write_constI(shader, buffer, TRUE);
917 return;
920 static void vs_2_srcreg(struct bc_writer *This,
921 const struct shader_reg *reg,
922 struct bytecode_buffer *buffer) {
923 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
924 DWORD has_swizzle;
925 DWORD component;
926 DWORD d3d9reg;
928 switch(reg->type) {
929 case BWRITERSPR_OUTPUT:
930 /* Map the swizzle to a writemask, the format expected
931 by map_vs_output
933 switch(reg->swizzle) {
934 case BWRITERVS_SWIZZLE_X:
935 component = BWRITERSP_WRITEMASK_0;
936 break;
937 case BWRITERVS_SWIZZLE_Y:
938 component = BWRITERSP_WRITEMASK_1;
939 break;
940 case BWRITERVS_SWIZZLE_Z:
941 component = BWRITERSP_WRITEMASK_2;
942 break;
943 case BWRITERVS_SWIZZLE_W:
944 component = BWRITERSP_WRITEMASK_3;
945 break;
946 default:
947 component = 0;
949 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
950 break;
952 case BWRITERSPR_RASTOUT:
953 case BWRITERSPR_ATTROUT:
954 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
955 * but are unexpected. If we hit this path it might be due to an error.
957 FIXME("Unexpected register type %u\n", reg->type);
958 /* drop through */
959 case BWRITERSPR_INPUT:
960 case BWRITERSPR_TEMP:
961 case BWRITERSPR_CONST:
962 case BWRITERSPR_ADDR:
963 case BWRITERSPR_CONSTINT:
964 case BWRITERSPR_CONSTBOOL:
965 case BWRITERSPR_LABEL:
966 d3d9reg = d3d9_register(reg->type);
967 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
968 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
969 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
970 break;
972 case BWRITERSPR_LOOP:
973 if(reg->regnum != 0) {
974 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
975 This->state = E_INVALIDARG;
976 return;
978 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
979 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
980 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
981 break;
983 case BWRITERSPR_PREDICATE:
984 if(This->version != BWRITERVS_VERSION(2, 1)){
985 WARN("Predicate register is allowed only in vs_2_x\n");
986 This->state = E_INVALIDARG;
987 return;
989 if(reg->regnum > 0) {
990 WARN("Only predicate register 0 is supported\n");
991 This->state = E_INVALIDARG;
992 return;
994 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
995 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
996 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
998 break;
1000 default:
1001 WARN("Invalid register type for 2.0 vshader\n");
1002 This->state = E_INVALIDARG;
1003 return;
1006 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1008 token |= d3d9_srcmod(reg->srcmod);
1010 if(reg->rel_reg)
1011 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1013 put_dword(buffer, token);
1015 /* vs_2_0 and newer write the register containing the index explicitly in the
1016 * binary code
1018 if(token & D3DVS_ADDRMODE_RELATIVE)
1019 vs_2_srcreg(This, reg->rel_reg, buffer);
1022 static void sm_2_opcode(struct bc_writer *This,
1023 const struct instruction *instr,
1024 DWORD token, struct bytecode_buffer *buffer) {
1025 /* From sm 2 onwards instruction length is encoded in the opcode field */
1026 int dsts = instr->has_dst ? 1 : 0;
1027 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
1028 if(instr->comptype)
1029 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1030 if(instr->has_predicate)
1031 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1032 put_dword(buffer,token);
1035 static const struct instr_handler_table vs_2_0_handlers[] = {
1036 {BWRITERSIO_ADD, instr_handler},
1037 {BWRITERSIO_NOP, instr_handler},
1038 {BWRITERSIO_MOV, instr_handler},
1039 {BWRITERSIO_SUB, instr_handler},
1040 {BWRITERSIO_MAD, instr_handler},
1041 {BWRITERSIO_MUL, instr_handler},
1042 {BWRITERSIO_RCP, instr_handler},
1043 {BWRITERSIO_RSQ, instr_handler},
1044 {BWRITERSIO_DP3, instr_handler},
1045 {BWRITERSIO_DP4, instr_handler},
1046 {BWRITERSIO_MIN, instr_handler},
1047 {BWRITERSIO_MAX, instr_handler},
1048 {BWRITERSIO_SLT, instr_handler},
1049 {BWRITERSIO_SGE, instr_handler},
1050 {BWRITERSIO_ABS, instr_handler},
1051 {BWRITERSIO_EXP, instr_handler},
1052 {BWRITERSIO_LOG, instr_handler},
1053 {BWRITERSIO_EXPP, instr_handler},
1054 {BWRITERSIO_LOGP, instr_handler},
1055 {BWRITERSIO_DST, instr_handler},
1056 {BWRITERSIO_LRP, instr_handler},
1057 {BWRITERSIO_FRC, instr_handler},
1058 {BWRITERSIO_CRS, instr_handler},
1059 {BWRITERSIO_SGN, instr_handler},
1060 {BWRITERSIO_NRM, instr_handler},
1061 {BWRITERSIO_SINCOS, instr_handler},
1062 {BWRITERSIO_M4x4, instr_handler},
1063 {BWRITERSIO_M4x3, instr_handler},
1064 {BWRITERSIO_M3x4, instr_handler},
1065 {BWRITERSIO_M3x3, instr_handler},
1066 {BWRITERSIO_M3x2, instr_handler},
1067 {BWRITERSIO_LIT, instr_handler},
1068 {BWRITERSIO_POW, instr_handler},
1069 {BWRITERSIO_MOVA, instr_handler},
1071 {BWRITERSIO_CALL, instr_handler},
1072 {BWRITERSIO_CALLNZ, instr_handler},
1073 {BWRITERSIO_REP, instr_handler},
1074 {BWRITERSIO_ENDREP, instr_handler},
1075 {BWRITERSIO_IF, instr_handler},
1076 {BWRITERSIO_LABEL, instr_handler},
1077 {BWRITERSIO_ELSE, instr_handler},
1078 {BWRITERSIO_ENDIF, instr_handler},
1079 {BWRITERSIO_LOOP, instr_handler},
1080 {BWRITERSIO_RET, instr_handler},
1081 {BWRITERSIO_ENDLOOP, instr_handler},
1083 {BWRITERSIO_END, NULL},
1086 static const struct bytecode_backend vs_2_0_backend = {
1087 vs_2_header,
1088 end,
1089 vs_2_srcreg,
1090 vs_12_dstreg,
1091 sm_2_opcode,
1092 vs_2_0_handlers
1095 static const struct instr_handler_table vs_2_x_handlers[] = {
1096 {BWRITERSIO_ADD, instr_handler},
1097 {BWRITERSIO_NOP, instr_handler},
1098 {BWRITERSIO_MOV, instr_handler},
1099 {BWRITERSIO_SUB, instr_handler},
1100 {BWRITERSIO_MAD, instr_handler},
1101 {BWRITERSIO_MUL, instr_handler},
1102 {BWRITERSIO_RCP, instr_handler},
1103 {BWRITERSIO_RSQ, instr_handler},
1104 {BWRITERSIO_DP3, instr_handler},
1105 {BWRITERSIO_DP4, instr_handler},
1106 {BWRITERSIO_MIN, instr_handler},
1107 {BWRITERSIO_MAX, instr_handler},
1108 {BWRITERSIO_SLT, instr_handler},
1109 {BWRITERSIO_SGE, instr_handler},
1110 {BWRITERSIO_ABS, instr_handler},
1111 {BWRITERSIO_EXP, instr_handler},
1112 {BWRITERSIO_LOG, instr_handler},
1113 {BWRITERSIO_EXPP, instr_handler},
1114 {BWRITERSIO_LOGP, instr_handler},
1115 {BWRITERSIO_DST, instr_handler},
1116 {BWRITERSIO_LRP, instr_handler},
1117 {BWRITERSIO_FRC, instr_handler},
1118 {BWRITERSIO_CRS, instr_handler},
1119 {BWRITERSIO_SGN, instr_handler},
1120 {BWRITERSIO_NRM, instr_handler},
1121 {BWRITERSIO_SINCOS, instr_handler},
1122 {BWRITERSIO_M4x4, instr_handler},
1123 {BWRITERSIO_M4x3, instr_handler},
1124 {BWRITERSIO_M3x4, instr_handler},
1125 {BWRITERSIO_M3x3, instr_handler},
1126 {BWRITERSIO_M3x2, instr_handler},
1127 {BWRITERSIO_LIT, instr_handler},
1128 {BWRITERSIO_POW, instr_handler},
1129 {BWRITERSIO_MOVA, instr_handler},
1131 {BWRITERSIO_CALL, instr_handler},
1132 {BWRITERSIO_CALLNZ, instr_handler},
1133 {BWRITERSIO_REP, instr_handler},
1134 {BWRITERSIO_ENDREP, instr_handler},
1135 {BWRITERSIO_IF, instr_handler},
1136 {BWRITERSIO_LABEL, instr_handler},
1137 {BWRITERSIO_IFC, instr_handler},
1138 {BWRITERSIO_ELSE, instr_handler},
1139 {BWRITERSIO_ENDIF, instr_handler},
1140 {BWRITERSIO_BREAK, instr_handler},
1141 {BWRITERSIO_BREAKC, instr_handler},
1142 {BWRITERSIO_LOOP, instr_handler},
1143 {BWRITERSIO_RET, instr_handler},
1144 {BWRITERSIO_ENDLOOP, instr_handler},
1146 {BWRITERSIO_SETP, instr_handler},
1147 {BWRITERSIO_BREAKP, instr_handler},
1149 {BWRITERSIO_END, NULL},
1152 static const struct bytecode_backend vs_2_x_backend = {
1153 vs_2_header,
1154 end,
1155 vs_2_srcreg,
1156 vs_12_dstreg,
1157 sm_2_opcode,
1158 vs_2_x_handlers
1161 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1162 DWORD i;
1163 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1164 DWORD token;
1165 const DWORD reg = (1<<31) |
1166 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
1167 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
1168 D3DSP_WRITEMASK_ALL;
1170 for(i = 0; i < shader->num_samplers; i++) {
1171 /* Write the DCL instruction */
1172 put_dword(buffer, instr_dcl);
1173 token = (1<<31);
1174 /* Already shifted */
1175 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
1176 put_dword(buffer, token);
1177 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1178 token |= d3d9_dstmod(shader->samplers[i].mod);
1179 put_dword(buffer, token);
1183 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1184 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1185 if(FAILED(hr)) {
1186 This->state = hr;
1187 return;
1190 /* Declare the shader type and version */
1191 put_dword(buffer, This->version);
1192 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1193 write_samplers(shader, buffer);
1194 write_constF(shader, buffer, TRUE);
1195 write_constB(shader, buffer, TRUE);
1196 write_constI(shader, buffer, TRUE);
1199 static void ps_2_srcreg(struct bc_writer *This,
1200 const struct shader_reg *reg,
1201 struct bytecode_buffer *buffer) {
1202 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1203 DWORD d3d9reg;
1204 if(reg->rel_reg) {
1205 WARN("Relative addressing not supported in <= ps_3_0\n");
1206 This->state = E_INVALIDARG;
1207 return;
1210 switch(reg->type) {
1211 case BWRITERSPR_INPUT:
1212 token |= map_ps_input(This, reg);
1213 break;
1215 /* Can be mapped 1:1 */
1216 case BWRITERSPR_TEMP:
1217 case BWRITERSPR_CONST:
1218 case BWRITERSPR_COLOROUT:
1219 case BWRITERSPR_CONSTBOOL:
1220 case BWRITERSPR_CONSTINT:
1221 case BWRITERSPR_SAMPLER:
1222 case BWRITERSPR_LABEL:
1223 case BWRITERSPR_DEPTHOUT:
1224 d3d9reg = d3d9_register(reg->type);
1225 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1226 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1227 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1228 break;
1230 case BWRITERSPR_PREDICATE:
1231 if(This->version != BWRITERPS_VERSION(2, 1)){
1232 WARN("Predicate register not supported in ps_2_0\n");
1233 This->state = E_INVALIDARG;
1235 if(reg->regnum) {
1236 WARN("Predicate register with regnum %u not supported\n",
1237 reg->regnum);
1238 This->state = E_INVALIDARG;
1240 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1241 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1242 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1243 break;
1245 default:
1246 WARN("Invalid register type for ps_2_0 shader\n");
1247 This->state = E_INVALIDARG;
1248 return;
1251 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1253 token |= d3d9_srcmod(reg->srcmod);
1254 put_dword(buffer, token);
1257 static void ps_2_0_dstreg(struct bc_writer *This,
1258 const struct shader_reg *reg,
1259 struct bytecode_buffer *buffer,
1260 DWORD shift, DWORD mod) {
1261 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1262 DWORD d3d9reg;
1264 if(reg->rel_reg) {
1265 WARN("Relative addressing not supported for destination registers\n");
1266 This->state = E_INVALIDARG;
1267 return;
1270 switch(reg->type) {
1271 case BWRITERSPR_TEMP: /* 1:1 mapping */
1272 case BWRITERSPR_COLOROUT:
1273 case BWRITERSPR_DEPTHOUT:
1274 d3d9reg = d3d9_register(reg->type);
1275 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1276 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1277 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1278 break;
1280 case BWRITERSPR_PREDICATE:
1281 if(This->version != BWRITERPS_VERSION(2, 1)){
1282 WARN("Predicate register not supported in ps_2_0\n");
1283 This->state = E_INVALIDARG;
1285 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1286 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1287 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1288 break;
1290 /* texkill uses the input register as a destination parameter */
1291 case BWRITERSPR_INPUT:
1292 token |= map_ps_input(This, reg);
1293 break;
1295 default:
1296 WARN("Invalid dest register type for 2.x pshader\n");
1297 This->state = E_INVALIDARG;
1298 return;
1301 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1302 token |= d3d9_dstmod(mod);
1304 token |= d3d9_writemask(reg->writemask);
1305 put_dword(buffer, token);
1308 static const struct instr_handler_table ps_2_0_handlers[] = {
1309 {BWRITERSIO_ADD, instr_handler},
1310 {BWRITERSIO_NOP, instr_handler},
1311 {BWRITERSIO_MOV, instr_handler},
1312 {BWRITERSIO_SUB, instr_handler},
1313 {BWRITERSIO_MAD, instr_handler},
1314 {BWRITERSIO_MUL, instr_handler},
1315 {BWRITERSIO_RCP, instr_handler},
1316 {BWRITERSIO_RSQ, instr_handler},
1317 {BWRITERSIO_DP3, instr_handler},
1318 {BWRITERSIO_DP4, instr_handler},
1319 {BWRITERSIO_MIN, instr_handler},
1320 {BWRITERSIO_MAX, instr_handler},
1321 {BWRITERSIO_ABS, instr_handler},
1322 {BWRITERSIO_EXP, instr_handler},
1323 {BWRITERSIO_LOG, instr_handler},
1324 {BWRITERSIO_EXPP, instr_handler},
1325 {BWRITERSIO_LOGP, instr_handler},
1326 {BWRITERSIO_LRP, instr_handler},
1327 {BWRITERSIO_FRC, instr_handler},
1328 {BWRITERSIO_CRS, instr_handler},
1329 {BWRITERSIO_NRM, instr_handler},
1330 {BWRITERSIO_SINCOS, instr_handler},
1331 {BWRITERSIO_M4x4, instr_handler},
1332 {BWRITERSIO_M4x3, instr_handler},
1333 {BWRITERSIO_M3x4, instr_handler},
1334 {BWRITERSIO_M3x3, instr_handler},
1335 {BWRITERSIO_M3x2, instr_handler},
1336 {BWRITERSIO_POW, instr_handler},
1337 {BWRITERSIO_DP2ADD, instr_handler},
1338 {BWRITERSIO_CMP, instr_handler},
1340 {BWRITERSIO_TEX, instr_handler},
1341 {BWRITERSIO_TEXLDP, instr_handler},
1342 {BWRITERSIO_TEXLDB, instr_handler},
1343 {BWRITERSIO_TEXKILL, instr_handler},
1345 {BWRITERSIO_END, NULL},
1348 static const struct bytecode_backend ps_2_0_backend = {
1349 ps_2_header,
1350 end,
1351 ps_2_srcreg,
1352 ps_2_0_dstreg,
1353 sm_2_opcode,
1354 ps_2_0_handlers
1357 static const struct instr_handler_table ps_2_x_handlers[] = {
1358 {BWRITERSIO_ADD, instr_handler},
1359 {BWRITERSIO_NOP, instr_handler},
1360 {BWRITERSIO_MOV, instr_handler},
1361 {BWRITERSIO_SUB, instr_handler},
1362 {BWRITERSIO_MAD, instr_handler},
1363 {BWRITERSIO_MUL, instr_handler},
1364 {BWRITERSIO_RCP, instr_handler},
1365 {BWRITERSIO_RSQ, instr_handler},
1366 {BWRITERSIO_DP3, instr_handler},
1367 {BWRITERSIO_DP4, instr_handler},
1368 {BWRITERSIO_MIN, instr_handler},
1369 {BWRITERSIO_MAX, instr_handler},
1370 {BWRITERSIO_ABS, instr_handler},
1371 {BWRITERSIO_EXP, instr_handler},
1372 {BWRITERSIO_LOG, instr_handler},
1373 {BWRITERSIO_EXPP, instr_handler},
1374 {BWRITERSIO_LOGP, instr_handler},
1375 {BWRITERSIO_LRP, instr_handler},
1376 {BWRITERSIO_FRC, instr_handler},
1377 {BWRITERSIO_CRS, instr_handler},
1378 {BWRITERSIO_NRM, instr_handler},
1379 {BWRITERSIO_SINCOS, instr_handler},
1380 {BWRITERSIO_M4x4, instr_handler},
1381 {BWRITERSIO_M4x3, instr_handler},
1382 {BWRITERSIO_M3x4, instr_handler},
1383 {BWRITERSIO_M3x3, instr_handler},
1384 {BWRITERSIO_M3x2, instr_handler},
1385 {BWRITERSIO_POW, instr_handler},
1386 {BWRITERSIO_DP2ADD, instr_handler},
1387 {BWRITERSIO_CMP, instr_handler},
1389 {BWRITERSIO_CALL, instr_handler},
1390 {BWRITERSIO_CALLNZ, instr_handler},
1391 {BWRITERSIO_REP, instr_handler},
1392 {BWRITERSIO_ENDREP, instr_handler},
1393 {BWRITERSIO_IF, instr_handler},
1394 {BWRITERSIO_LABEL, instr_handler},
1395 {BWRITERSIO_IFC, instr_handler},
1396 {BWRITERSIO_ELSE, instr_handler},
1397 {BWRITERSIO_ENDIF, instr_handler},
1398 {BWRITERSIO_BREAK, instr_handler},
1399 {BWRITERSIO_BREAKC, instr_handler},
1400 {BWRITERSIO_RET, instr_handler},
1402 {BWRITERSIO_TEX, instr_handler},
1403 {BWRITERSIO_TEXLDP, instr_handler},
1404 {BWRITERSIO_TEXLDB, instr_handler},
1405 {BWRITERSIO_TEXKILL, instr_handler},
1406 {BWRITERSIO_DSX, instr_handler},
1407 {BWRITERSIO_DSY, instr_handler},
1409 {BWRITERSIO_SETP, instr_handler},
1410 {BWRITERSIO_BREAKP, instr_handler},
1412 {BWRITERSIO_TEXLDD, instr_handler},
1414 {BWRITERSIO_END, NULL},
1417 static const struct bytecode_backend ps_2_x_backend = {
1418 ps_2_header,
1419 end,
1420 ps_2_srcreg,
1421 ps_2_0_dstreg,
1422 sm_2_opcode,
1423 ps_2_x_handlers
1426 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1427 /* Declare the shader type and version */
1428 put_dword(buffer, This->version);
1430 write_declarations(This, buffer, TRUE, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1431 write_declarations(This, buffer, TRUE, shader->outputs, shader->num_outputs, BWRITERSPR_OUTPUT);
1432 write_constF(shader, buffer, TRUE);
1433 write_constB(shader, buffer, TRUE);
1434 write_constI(shader, buffer, TRUE);
1435 write_samplers(shader, buffer);
1436 return;
1439 static void sm_3_srcreg(struct bc_writer *This,
1440 const struct shader_reg *reg,
1441 struct bytecode_buffer *buffer) {
1442 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1443 DWORD d3d9reg;
1445 d3d9reg = d3d9_register(reg->type);
1446 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1447 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1448 token |= reg->regnum & D3DSP_REGNUM_MASK;
1450 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
1451 token |= d3d9_srcmod(reg->srcmod);
1453 if(reg->rel_reg) {
1454 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
1455 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
1456 This->state = E_INVALIDARG;
1457 return;
1459 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
1460 reg->rel_reg->type == BWRITERSPR_LOOP) &&
1461 reg->rel_reg->regnum == 0) {
1462 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1463 } else {
1464 WARN("Unsupported relative addressing register\n");
1465 This->state = E_INVALIDARG;
1466 return;
1470 put_dword(buffer, token);
1472 /* vs_2_0 and newer write the register containing the index explicitly in the
1473 * binary code
1475 if(token & D3DVS_ADDRMODE_RELATIVE) {
1476 sm_3_srcreg(This, reg->rel_reg, buffer);
1480 static void sm_3_dstreg(struct bc_writer *This,
1481 const struct shader_reg *reg,
1482 struct bytecode_buffer *buffer,
1483 DWORD shift, DWORD mod) {
1484 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1485 DWORD d3d9reg;
1487 if(reg->rel_reg) {
1488 if(This->version == BWRITERVS_VERSION(3, 0) &&
1489 reg->type == BWRITERSPR_OUTPUT) {
1490 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1491 } else {
1492 WARN("Relative addressing not supported for this shader type or register type\n");
1493 This->state = E_INVALIDARG;
1494 return;
1498 d3d9reg = d3d9_register(reg->type);
1499 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1500 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1501 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1503 token |= d3d9_dstmod(mod);
1505 token |= d3d9_writemask(reg->writemask);
1506 put_dword(buffer, token);
1508 /* vs_2_0 and newer write the register containing the index explicitly in the
1509 * binary code
1511 if(token & D3DVS_ADDRMODE_RELATIVE) {
1512 sm_3_srcreg(This, reg->rel_reg, buffer);
1516 static const struct instr_handler_table vs_3_handlers[] = {
1517 {BWRITERSIO_ADD, instr_handler},
1518 {BWRITERSIO_NOP, instr_handler},
1519 {BWRITERSIO_MOV, instr_handler},
1520 {BWRITERSIO_SUB, instr_handler},
1521 {BWRITERSIO_MAD, instr_handler},
1522 {BWRITERSIO_MUL, instr_handler},
1523 {BWRITERSIO_RCP, instr_handler},
1524 {BWRITERSIO_RSQ, instr_handler},
1525 {BWRITERSIO_DP3, instr_handler},
1526 {BWRITERSIO_DP4, instr_handler},
1527 {BWRITERSIO_MIN, instr_handler},
1528 {BWRITERSIO_MAX, instr_handler},
1529 {BWRITERSIO_SLT, instr_handler},
1530 {BWRITERSIO_SGE, instr_handler},
1531 {BWRITERSIO_ABS, instr_handler},
1532 {BWRITERSIO_EXP, instr_handler},
1533 {BWRITERSIO_LOG, instr_handler},
1534 {BWRITERSIO_EXPP, instr_handler},
1535 {BWRITERSIO_LOGP, instr_handler},
1536 {BWRITERSIO_DST, instr_handler},
1537 {BWRITERSIO_LRP, instr_handler},
1538 {BWRITERSIO_FRC, instr_handler},
1539 {BWRITERSIO_CRS, instr_handler},
1540 {BWRITERSIO_SGN, instr_handler},
1541 {BWRITERSIO_NRM, instr_handler},
1542 {BWRITERSIO_SINCOS, instr_handler},
1543 {BWRITERSIO_M4x4, instr_handler},
1544 {BWRITERSIO_M4x3, instr_handler},
1545 {BWRITERSIO_M3x4, instr_handler},
1546 {BWRITERSIO_M3x3, instr_handler},
1547 {BWRITERSIO_M3x2, instr_handler},
1548 {BWRITERSIO_LIT, instr_handler},
1549 {BWRITERSIO_POW, instr_handler},
1550 {BWRITERSIO_MOVA, instr_handler},
1552 {BWRITERSIO_CALL, instr_handler},
1553 {BWRITERSIO_CALLNZ, instr_handler},
1554 {BWRITERSIO_REP, instr_handler},
1555 {BWRITERSIO_ENDREP, instr_handler},
1556 {BWRITERSIO_IF, instr_handler},
1557 {BWRITERSIO_LABEL, instr_handler},
1558 {BWRITERSIO_IFC, instr_handler},
1559 {BWRITERSIO_ELSE, instr_handler},
1560 {BWRITERSIO_ENDIF, instr_handler},
1561 {BWRITERSIO_BREAK, instr_handler},
1562 {BWRITERSIO_BREAKC, instr_handler},
1563 {BWRITERSIO_LOOP, instr_handler},
1564 {BWRITERSIO_RET, instr_handler},
1565 {BWRITERSIO_ENDLOOP, instr_handler},
1567 {BWRITERSIO_SETP, instr_handler},
1568 {BWRITERSIO_BREAKP, instr_handler},
1569 {BWRITERSIO_TEXLDL, instr_handler},
1571 {BWRITERSIO_END, NULL},
1574 static const struct bytecode_backend vs_3_backend = {
1575 sm_3_header,
1576 end,
1577 sm_3_srcreg,
1578 sm_3_dstreg,
1579 sm_2_opcode,
1580 vs_3_handlers
1583 static const struct instr_handler_table ps_3_handlers[] = {
1584 {BWRITERSIO_ADD, instr_handler},
1585 {BWRITERSIO_NOP, instr_handler},
1586 {BWRITERSIO_MOV, instr_handler},
1587 {BWRITERSIO_SUB, instr_handler},
1588 {BWRITERSIO_MAD, instr_handler},
1589 {BWRITERSIO_MUL, instr_handler},
1590 {BWRITERSIO_RCP, instr_handler},
1591 {BWRITERSIO_RSQ, instr_handler},
1592 {BWRITERSIO_DP3, instr_handler},
1593 {BWRITERSIO_DP4, instr_handler},
1594 {BWRITERSIO_MIN, instr_handler},
1595 {BWRITERSIO_MAX, instr_handler},
1596 {BWRITERSIO_ABS, instr_handler},
1597 {BWRITERSIO_EXP, instr_handler},
1598 {BWRITERSIO_LOG, instr_handler},
1599 {BWRITERSIO_EXPP, instr_handler},
1600 {BWRITERSIO_LOGP, instr_handler},
1601 {BWRITERSIO_LRP, instr_handler},
1602 {BWRITERSIO_FRC, instr_handler},
1603 {BWRITERSIO_CRS, instr_handler},
1604 {BWRITERSIO_NRM, instr_handler},
1605 {BWRITERSIO_SINCOS, instr_handler},
1606 {BWRITERSIO_M4x4, instr_handler},
1607 {BWRITERSIO_M4x3, instr_handler},
1608 {BWRITERSIO_M3x4, instr_handler},
1609 {BWRITERSIO_M3x3, instr_handler},
1610 {BWRITERSIO_M3x2, instr_handler},
1611 {BWRITERSIO_POW, instr_handler},
1612 {BWRITERSIO_DP2ADD, instr_handler},
1613 {BWRITERSIO_CMP, instr_handler},
1615 {BWRITERSIO_CALL, instr_handler},
1616 {BWRITERSIO_CALLNZ, instr_handler},
1617 {BWRITERSIO_REP, instr_handler},
1618 {BWRITERSIO_ENDREP, instr_handler},
1619 {BWRITERSIO_IF, instr_handler},
1620 {BWRITERSIO_LABEL, instr_handler},
1621 {BWRITERSIO_IFC, instr_handler},
1622 {BWRITERSIO_ELSE, instr_handler},
1623 {BWRITERSIO_ENDIF, instr_handler},
1624 {BWRITERSIO_BREAK, instr_handler},
1625 {BWRITERSIO_BREAKC, instr_handler},
1626 {BWRITERSIO_LOOP, instr_handler},
1627 {BWRITERSIO_RET, instr_handler},
1628 {BWRITERSIO_ENDLOOP, instr_handler},
1630 {BWRITERSIO_SETP, instr_handler},
1631 {BWRITERSIO_BREAKP, instr_handler},
1632 {BWRITERSIO_TEXLDL, instr_handler},
1634 {BWRITERSIO_TEX, instr_handler},
1635 {BWRITERSIO_TEXLDP, instr_handler},
1636 {BWRITERSIO_TEXLDB, instr_handler},
1637 {BWRITERSIO_TEXKILL, instr_handler},
1638 {BWRITERSIO_DSX, instr_handler},
1639 {BWRITERSIO_DSY, instr_handler},
1640 {BWRITERSIO_TEXLDD, instr_handler},
1642 {BWRITERSIO_END, NULL},
1645 static const struct bytecode_backend ps_3_backend = {
1646 sm_3_header,
1647 end,
1648 sm_3_srcreg,
1649 sm_3_dstreg,
1650 sm_2_opcode,
1651 ps_3_handlers
1654 static void init_vs10_dx9_writer(struct bc_writer *writer) {
1655 TRACE("Creating DirectX9 vertex shader 1.0 writer\n");
1656 writer->funcs = &vs_1_x_backend;
1659 static void init_vs11_dx9_writer(struct bc_writer *writer) {
1660 TRACE("Creating DirectX9 vertex shader 1.1 writer\n");
1661 writer->funcs = &vs_1_x_backend;
1664 static void init_vs20_dx9_writer(struct bc_writer *writer) {
1665 TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
1666 writer->funcs = &vs_2_0_backend;
1669 static void init_vs2x_dx9_writer(struct bc_writer *writer) {
1670 TRACE("Creating DirectX9 vertex shader 2.x writer\n");
1671 writer->funcs = &vs_2_x_backend;
1674 static void init_vs30_dx9_writer(struct bc_writer *writer) {
1675 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
1676 writer->funcs = &vs_3_backend;
1679 static void init_ps20_dx9_writer(struct bc_writer *writer) {
1680 TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
1681 writer->funcs = &ps_2_0_backend;
1684 static void init_ps2x_dx9_writer(struct bc_writer *writer) {
1685 TRACE("Creating DirectX9 pixel shader 2.x writer\n");
1686 writer->funcs = &ps_2_x_backend;
1689 static void init_ps30_dx9_writer(struct bc_writer *writer) {
1690 TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
1691 writer->funcs = &ps_3_backend;
1694 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
1695 struct bc_writer *ret = asm_alloc(sizeof(*ret));
1697 if(!ret) {
1698 WARN("Failed to allocate a bytecode writer instance\n");
1699 return NULL;
1702 switch(version) {
1703 case BWRITERVS_VERSION(1, 0):
1704 if(dxversion != 9) {
1705 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
1706 goto fail;
1708 init_vs10_dx9_writer(ret);
1709 break;
1710 case BWRITERVS_VERSION(1, 1):
1711 if(dxversion != 9) {
1712 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
1713 goto fail;
1715 init_vs11_dx9_writer(ret);
1716 break;
1717 case BWRITERVS_VERSION(2, 0):
1718 if(dxversion != 9) {
1719 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
1720 goto fail;
1722 init_vs20_dx9_writer(ret);
1723 break;
1724 case BWRITERVS_VERSION(2, 1):
1725 if(dxversion != 9) {
1726 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
1727 goto fail;
1729 init_vs2x_dx9_writer(ret);
1730 break;
1731 case BWRITERVS_VERSION(3, 0):
1732 if(dxversion != 9) {
1733 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
1734 goto fail;
1736 init_vs30_dx9_writer(ret);
1737 break;
1739 case BWRITERPS_VERSION(1, 0):
1740 if(dxversion != 9) {
1741 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
1742 goto fail;
1744 /* TODO: Set the appropriate writer backend */
1745 break;
1746 case BWRITERPS_VERSION(1, 1):
1747 if(dxversion != 9) {
1748 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
1749 goto fail;
1751 /* TODO: Set the appropriate writer backend */
1752 break;
1753 case BWRITERPS_VERSION(1, 2):
1754 if(dxversion != 9) {
1755 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
1756 goto fail;
1758 /* TODO: Set the appropriate writer backend */
1759 break;
1760 case BWRITERPS_VERSION(1, 3):
1761 if(dxversion != 9) {
1762 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
1763 goto fail;
1765 /* TODO: Set the appropriate writer backend */
1766 break;
1767 case BWRITERPS_VERSION(1, 4):
1768 if(dxversion != 9) {
1769 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
1770 goto fail;
1772 /* TODO: Set the appropriate writer backend */
1773 break;
1775 case BWRITERPS_VERSION(2, 0):
1776 if(dxversion != 9) {
1777 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
1778 goto fail;
1780 init_ps20_dx9_writer(ret);
1781 break;
1783 case BWRITERPS_VERSION(2, 1):
1784 if(dxversion != 9) {
1785 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
1786 goto fail;
1788 init_ps2x_dx9_writer(ret);
1789 break;
1791 case BWRITERPS_VERSION(3, 0):
1792 if(dxversion != 9) {
1793 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
1794 goto fail;
1796 init_ps30_dx9_writer(ret);
1797 break;
1799 default:
1800 WARN("Unexpected shader version requested: %08x\n", version);
1801 goto fail;
1803 ret->version = version;
1804 return ret;
1806 fail:
1807 asm_free(ret);
1808 return NULL;
1811 static HRESULT call_instr_handler(struct bc_writer *writer,
1812 const struct instruction *instr,
1813 struct bytecode_buffer *buffer) {
1814 DWORD i=0;
1816 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
1817 if(instr->opcode == writer->funcs->instructions[i].opcode) {
1818 if(!writer->funcs->instructions[i].func) {
1819 WARN("Opcode %u not supported by this profile\n", instr->opcode);
1820 return E_INVALIDARG;
1822 writer->funcs->instructions[i].func(writer, instr, buffer);
1823 return S_OK;
1825 i++;
1828 FIXME("Unhandled instruction %u\n", instr->opcode);
1829 return E_INVALIDARG;
1832 /* SlWriteBytecode (wineshader.@)
1834 * Writes shader version specific bytecode from the shader passed in.
1835 * The returned bytecode can be passed to the Direct3D runtime like
1836 * IDirect3DDevice9::Create*Shader.
1838 * Parameters:
1839 * shader: Shader to translate into bytecode
1840 * version: Shader version to generate(d3d version token)
1841 * dxversion: DirectX version the code targets
1842 * result: the resulting shader bytecode
1844 * Return values:
1845 * S_OK on success
1847 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
1848 struct bc_writer *writer;
1849 struct bytecode_buffer *buffer = NULL;
1850 HRESULT hr;
1851 unsigned int i;
1853 if(!shader){
1854 ERR("NULL shader structure, aborting\n");
1855 return E_FAIL;
1857 writer = create_writer(shader->version, dxversion);
1858 *result = NULL;
1860 if(!writer) {
1861 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
1862 WARN("or out of memory\n");
1863 hr = E_FAIL;
1864 goto error;
1867 buffer = allocate_buffer();
1868 if(!buffer) {
1869 WARN("Failed to allocate a buffer for the shader bytecode\n");
1870 hr = E_FAIL;
1871 goto error;
1874 writer->funcs->header(writer, shader, buffer);
1875 if(FAILED(writer->state)) {
1876 hr = writer->state;
1877 goto error;
1880 for(i = 0; i < shader->num_instrs; i++) {
1881 hr = call_instr_handler(writer, shader->instr[i], buffer);
1882 if(FAILED(hr)) {
1883 goto error;
1887 if(FAILED(writer->state)) {
1888 hr = writer->state;
1889 goto error;
1892 writer->funcs->end(writer, shader, buffer);
1894 if(FAILED(buffer->state)) {
1895 hr = buffer->state;
1896 goto error;
1899 /* Cut off unneeded memory from the result buffer */
1900 *result = asm_realloc(buffer->data,
1901 sizeof(DWORD) * buffer->size);
1902 if(!*result) {
1903 *result = buffer->data;
1905 buffer->data = NULL;
1906 hr = S_OK;
1908 error:
1909 if(buffer) {
1910 asm_free(buffer->data);
1911 asm_free(buffer);
1913 asm_free(writer);
1914 return hr;
1917 void SlDeleteShader(struct bwriter_shader *shader) {
1918 unsigned int i, j;
1920 TRACE("Deleting shader %p\n", shader);
1922 for(i = 0; i < shader->num_cf; i++) {
1923 asm_free(shader->constF[i]);
1925 asm_free(shader->constF);
1926 for(i = 0; i < shader->num_ci; i++) {
1927 asm_free(shader->constI[i]);
1929 asm_free(shader->constI);
1930 for(i = 0; i < shader->num_cb; i++) {
1931 asm_free(shader->constB[i]);
1933 asm_free(shader->constB);
1935 asm_free(shader->inputs);
1936 asm_free(shader->outputs);
1937 asm_free(shader->samplers);
1939 for(i = 0; i < shader->num_instrs; i++) {
1940 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
1941 asm_free(shader->instr[i]->src[j].rel_reg);
1943 asm_free(shader->instr[i]->src);
1944 asm_free(shader->instr[i]);
1946 asm_free(shader->instr);
1948 asm_free(shader);