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
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
39 * srcs: Number of source registers to allocate
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));
48 ERR("Failed to allocate memory for an instruction structure\n");
53 ret->src = asm_alloc(srcs * sizeof(*ret->src));
55 ERR("Failed to allocate memory for instruction registers\n");
64 /* void add_instruction
66 * Adds a new instruction to the shader's instructions array and grows the instruction array
69 * The function does NOT copy the instruction structure. Make sure not to release the
70 * instruction or any of its substructures like registers.
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);
84 ERR("Failed to allocate the shader instruction array\n");
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");
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");
102 shader->instr[shader->num_instrs] = instr;
103 shader->num_instrs++;
107 BOOL add_constF(struct bwriter_shader *shader, DWORD reg, float x, float y, float z, float w) {
108 struct constant *newconst;
111 struct constant **newarray;
112 newarray = asm_realloc(shader->constF,
113 sizeof(*shader->constF) * (shader->num_cf + 1));
115 ERR("Failed to grow the constants array\n");
118 shader->constF = newarray;
120 shader->constF = asm_alloc(sizeof(*shader->constF));
121 if(!shader->constF) {
122 ERR("Failed to allocate the constants array\n");
127 newconst = asm_alloc(sizeof(*newconst));
129 ERR("Failed to allocate a new constant\n");
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;
143 BOOL add_constI(struct bwriter_shader *shader, DWORD reg, INT x, INT y, INT z, INT w) {
144 struct constant *newconst;
147 struct constant **newarray;
148 newarray = asm_realloc(shader->constI,
149 sizeof(*shader->constI) * (shader->num_ci + 1));
151 ERR("Failed to grow the constants array\n");
154 shader->constI = newarray;
156 shader->constI = asm_alloc(sizeof(*shader->constI));
157 if(!shader->constI) {
158 ERR("Failed to allocate the constants array\n");
163 newconst = asm_alloc(sizeof(*newconst));
165 ERR("Failed to allocate a new constant\n");
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;
179 BOOL add_constB(struct bwriter_shader *shader, DWORD reg, BOOL x) {
180 struct constant *newconst;
183 struct constant **newarray;
184 newarray = asm_realloc(shader->constB,
185 sizeof(*shader->constB) * (shader->num_cb + 1));
187 ERR("Failed to grow the constants array\n");
190 shader->constB = newarray;
192 shader->constB = asm_alloc(sizeof(*shader->constB));
193 if(!shader->constB) {
194 ERR("Failed to allocate the constants array\n");
199 newconst = asm_alloc(sizeof(*newconst));
201 ERR("Failed to allocate a new constant\n");
204 newconst->regnum = reg;
205 newconst->value[0].b = x;
206 shader->constB[shader->num_cb] = newconst;
212 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) {
214 struct declaration **decl;
217 if(!shader) return FALSE;
220 num = &shader->num_outputs;
221 decl = &shader->outputs;
223 num = &shader->num_inputs;
224 decl = &shader->inputs;
228 *decl = asm_alloc(sizeof(**decl));
230 ERR("Error allocating declarations array\n");
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));
245 ERR("Error reallocating declarations array\n");
250 (*decl)[*num].usage = usage;
251 (*decl)[*num].usage_idx = usage_idx;
252 (*decl)[*num].regnum = regnum;
253 (*decl)[*num].writemask = writemask;
259 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD regnum) {
262 if(!shader) return FALSE;
264 if(shader->num_samplers == 0) {
265 shader->samplers = asm_alloc(sizeof(*shader->samplers));
266 if(!shader->samplers) {
267 ERR("Error allocating samplers array\n");
271 struct samplerdecl *newarray;
273 for(i = 0; i < shader->num_samplers; i++) {
274 if(shader->samplers[i].regnum == regnum) {
275 WARN("Sampler %u already declared\n", regnum);
276 /* This is not an error as far as the assembler is concerned.
277 * Direct3D might refuse to load the compiled shader though
282 newarray = asm_realloc(shader->samplers,
283 sizeof(*shader->samplers) * (shader->num_samplers + 1));
285 ERR("Error reallocating samplers array\n");
288 shader->samplers = newarray;
291 shader->samplers[shader->num_samplers].type = samptype;
292 shader->samplers[shader->num_samplers].regnum = regnum;
293 shader->num_samplers++;
298 /* shader bytecode buffer manipulation functions.
299 * allocate_buffer creates a new buffer structure, put_dword adds a new
300 * DWORD to the buffer. In the rare case of a memory allocation failure
301 * when trying to grow the buffer a flag is set in the buffer to mark it
302 * invalid. This avoids return value checking and passing in many places
304 static struct bytecode_buffer *allocate_buffer(void) {
305 struct bytecode_buffer *ret;
307 ret = asm_alloc(sizeof(*ret));
308 if(!ret) return NULL;
310 ret->alloc_size = BYTECODEBUFFER_INITIAL_SIZE;
311 ret->data = asm_alloc(sizeof(DWORD) * ret->alloc_size);
320 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
321 if(FAILED(buffer->state)) return;
323 if(buffer->alloc_size == buffer->size) {
325 buffer->alloc_size *= 2;
326 newarray = asm_realloc(buffer->data,
327 sizeof(DWORD) * buffer->alloc_size);
329 ERR("Failed to grow the buffer data memory\n");
330 buffer->state = E_OUTOFMEMORY;
333 buffer->data = newarray;
335 buffer->data[buffer->size++] = value;
338 /******************************************************
339 * Implementation of the writer functions starts here *
340 ******************************************************/
341 static void write_declarations(struct bytecode_buffer *buffer, BOOL len,
342 const struct declaration *decls, unsigned int num, DWORD type) {
344 DWORD instr_dcl = D3DSIO_DCL;
348 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
351 for(i = 0; i < num; i++) {
352 /* Write the DCL instruction */
353 put_dword(buffer, instr_dcl);
355 /* Write the usage and index */
356 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
357 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
358 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
359 put_dword(buffer, token);
361 /* Write the dest register */
362 token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */
363 token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
364 token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL;
365 token |= decls[i].regnum & D3DSP_REGNUM_MASK;
366 put_dword(buffer, token);
370 static void write_const(struct constant **consts, int num, DWORD opcode, DWORD reg_type, struct bytecode_buffer *buffer, BOOL len) {
372 DWORD instr_def = opcode;
373 const DWORD reg = (1<<31) |
374 ((reg_type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
375 ((reg_type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
379 if(opcode == D3DSIO_DEFB)
380 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
382 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
385 for(i = 0; i < num; i++) {
386 /* Write the DEF instruction */
387 put_dword(buffer, instr_def);
389 put_dword(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
390 put_dword(buffer, consts[i]->value[0].d);
391 if(opcode != D3DSIO_DEFB) {
392 put_dword(buffer, consts[i]->value[1].d);
393 put_dword(buffer, consts[i]->value[2].d);
394 put_dword(buffer, consts[i]->value[3].d);
399 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
400 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
403 static HRESULT vs_find_builtin_varyings(struct bc_writer *This, const struct bwriter_shader *shader) {
405 DWORD usage, usage_idx, writemask, regnum;
407 for(i = 0; i < shader->num_outputs; i++) {
408 usage = shader->outputs[i].usage;
409 usage_idx = shader->outputs[i].usage_idx;
410 writemask = shader->outputs[i].writemask;
411 regnum = shader->outputs[i].regnum;
414 case BWRITERDECLUSAGE_POSITION:
415 case BWRITERDECLUSAGE_POSITIONT:
417 WARN("dcl_position%u not supported in sm 1/2 shaders\n", usage_idx);
420 TRACE("o%u is oPos\n", regnum);
421 This->oPos_regnum = regnum;
424 case BWRITERDECLUSAGE_COLOR:
426 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
429 if(writemask != BWRITERSP_WRITEMASK_ALL) {
430 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
433 TRACE("o%u is oD%u\n", regnum, usage_idx);
434 This->oD_regnum[usage_idx] = regnum;
437 case BWRITERDECLUSAGE_TEXCOORD:
439 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
442 if(writemask != (BWRITERSP_WRITEMASK_0) &&
443 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
444 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
445 writemask != (BWRITERSP_WRITEMASK_ALL)) {
446 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
449 TRACE("o%u is oT%u\n", regnum, usage_idx);
450 This->oT_regnum[usage_idx] = regnum;
453 case BWRITERDECLUSAGE_PSIZE:
455 WARN("dcl_psize%u not supported in sm 1/2 shaders\n", usage_idx);
458 TRACE("o%u writemask 0x%08x is oPts\n", regnum, writemask);
459 This->oPts_regnum = regnum;
460 This->oPts_mask = writemask;
463 case BWRITERDECLUSAGE_FOG:
465 WARN("dcl_fog%u not supported in sm 1 shaders\n", usage_idx);
468 if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
469 writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
470 WARN("Unsupported fog writemask\n");
473 TRACE("o%u writemask 0x%08x is oFog\n", regnum, writemask);
474 This->oFog_regnum = regnum;
475 This->oFog_mask = writemask;
479 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
487 static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
488 const struct bwriter_shader *shader,
491 DWORD usage, usage_idx, writemask, regnum;
493 This->v_regnum[0] = -1; This->v_regnum[1] = -1;
494 for(i = 0; i < 8; i++) This->t_regnum[i] = -1;
496 for(i = 0; i < shader->num_inputs; i++) {
497 usage = shader->inputs[i].usage;
498 usage_idx = shader->inputs[i].usage_idx;
499 writemask = shader->inputs[i].writemask;
500 regnum = shader->inputs[i].regnum;
503 case BWRITERDECLUSAGE_COLOR:
505 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
508 if(writemask != BWRITERSP_WRITEMASK_ALL) {
509 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
512 TRACE("v%u is v%u\n", regnum, usage_idx);
513 This->v_regnum[usage_idx] = regnum;
516 case BWRITERDECLUSAGE_TEXCOORD:
517 if(usage_idx > texcoords) {
518 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
521 if(writemask != (BWRITERSP_WRITEMASK_0) &&
522 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
523 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
524 writemask != (BWRITERSP_WRITEMASK_ALL)) {
525 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
527 writemask = BWRITERSP_WRITEMASK_ALL;
529 TRACE("v%u is t%u\n", regnum, usage_idx);
530 This->t_regnum[usage_idx] = regnum;
534 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
542 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
543 put_dword(buffer, D3DSIO_END);
546 static DWORD map_vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
550 *has_components = TRUE;
551 if(regnum == This->oPos_regnum) {
552 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
553 token |= D3DSRO_POSITION & D3DSP_REGNUM_MASK; /* No shift */
556 if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
557 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
558 token |= D3DSRO_FOG & D3DSP_REGNUM_MASK; /* No shift */
559 token |= D3DSP_WRITEMASK_ALL;
560 *has_components = FALSE;
563 if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
564 token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
565 token |= D3DSRO_POINT_SIZE & D3DSP_REGNUM_MASK; /* No shift */
566 token |= D3DSP_WRITEMASK_ALL;
567 *has_components = FALSE;
570 for(i = 0; i < 2; i++) {
571 if(regnum == This->oD_regnum[i]) {
572 token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
573 token |= i & D3DSP_REGNUM_MASK; /* No shift */
577 for(i = 0; i < 8; i++) {
578 if(regnum == This->oT_regnum[i]) {
579 token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
580 token |= i & D3DSP_REGNUM_MASK; /* No shift */
585 /* The varying must be undeclared - if an unsupported varying was declared,
586 * the vs_find_builtin_varyings function would have caught it and this code
588 WARN("Undeclared varying %u\n", regnum);
589 This->state = E_INVALIDARG;
593 static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
594 struct bytecode_buffer *buffer,
595 DWORD shift, DWORD mod) {
596 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
600 WARN("Relative addressing not supported for destination registers\n");
601 This->state = E_INVALIDARG;
606 case BWRITERSPR_OUTPUT:
607 token |= map_vs_output(This, reg->regnum, reg->writemask, &has_wmask);
610 case BWRITERSPR_RASTOUT:
611 case BWRITERSPR_ATTROUT:
612 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
613 * but are unexpected. If we hit this path it might be due to an error.
615 FIXME("Unexpected register type %u\n", reg->type);
617 case BWRITERSPR_INPUT:
618 case BWRITERSPR_TEMP:
619 case BWRITERSPR_CONST:
620 token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
621 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
625 case BWRITERSPR_ADDR:
626 if(reg->regnum != 0) {
627 WARN("Only a0 exists\n");
628 This->state = E_INVALIDARG;
631 token |= (D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
632 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
636 case BWRITERSPR_PREDICATE:
637 if(This->version != BWRITERVS_VERSION(2, 1)){
638 WARN("Predicate register is allowed only in vs_2_x\n");
639 This->state = E_INVALIDARG;
642 if(reg->regnum != 0) {
643 WARN("Only predicate register p0 exists\n");
644 This->state = E_INVALIDARG;
647 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
648 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
649 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
654 WARN("Invalid register type for 1.x-2.x vertex shader\n");
655 This->state = E_INVALIDARG;
659 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
660 * into the bytecode and since the compiler doesn't do such checks write them
661 * (the checks are done by the undocumented shader validator)
663 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
664 token |= d3d9_dstmod(mod);
667 token |= d3d9_writemask(reg->writemask);
669 put_dword(buffer, token);
672 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
673 struct bytecode_buffer *buffer){
675 if(instr->has_predicate){
676 This->funcs->srcreg(This, &instr->predicate, buffer);
678 for(i = 0; i < instr->num_srcs; i++){
679 This->funcs->srcreg(This, &instr->src[i], buffer);
683 static DWORD map_ps_input(struct bc_writer *This,
684 const struct shader_reg *reg) {
686 /* Map color interpolators */
687 for(i = 0; i < 2; i++) {
688 if(reg->regnum == This->v_regnum[i]) {
689 token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
690 token |= i & D3DSP_REGNUM_MASK; /* No shift */
694 for(i = 0; i < 8; i++) {
695 if(reg->regnum == This->t_regnum[i]) {
696 token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
697 token |= i & D3DSP_REGNUM_MASK; /* No shift */
702 WARN("Invalid ps 1/2 varying\n");
703 This->state = E_INVALIDARG;
707 /* The length of an instruction consists of the destination register (if any),
708 * the number of source registers, the number of address registers used for
709 * indirect addressing, and optionally the predicate register
711 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
713 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
716 if(instr->dst.rel_reg) ret++;
718 for(i = 0; i < srcs; i++) {
719 if(instr->src[i].rel_reg) ret++;
724 static void instr_handler(struct bc_writer *This,
725 const struct instruction *instr,
726 struct bytecode_buffer *buffer) {
727 DWORD token = d3d9_opcode(instr->opcode);
728 TRACE("token: %x\n", token);
730 This->funcs->opcode(This, instr, token, buffer);
731 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
732 write_srcregs(This, instr, buffer);
735 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
736 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
739 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
740 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
743 static void vs_2_header(struct bc_writer *This,
744 const struct bwriter_shader *shader,
745 struct bytecode_buffer *buffer) {
748 hr = vs_find_builtin_varyings(This, shader);
754 /* Declare the shader type and version */
755 put_dword(buffer, This->version);
757 write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
758 write_constF(shader, buffer, TRUE);
759 write_constB(shader, buffer, TRUE);
760 write_constI(shader, buffer, TRUE);
764 static void vs_2_srcreg(struct bc_writer *This,
765 const struct shader_reg *reg,
766 struct bytecode_buffer *buffer) {
767 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
773 case BWRITERSPR_OUTPUT:
774 /* Map the swizzle to a writemask, the format expected
777 switch(reg->swizzle) {
778 case BWRITERVS_SWIZZLE_X:
779 component = BWRITERSP_WRITEMASK_0;
781 case BWRITERVS_SWIZZLE_Y:
782 component = BWRITERSP_WRITEMASK_1;
784 case BWRITERVS_SWIZZLE_Z:
785 component = BWRITERSP_WRITEMASK_2;
787 case BWRITERVS_SWIZZLE_W:
788 component = BWRITERSP_WRITEMASK_3;
793 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
796 case BWRITERSPR_RASTOUT:
797 case BWRITERSPR_ATTROUT:
798 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
799 * but are unexpected. If we hit this path it might be due to an error.
801 FIXME("Unexpected register type %u\n", reg->type);
803 case BWRITERSPR_INPUT:
804 case BWRITERSPR_TEMP:
805 case BWRITERSPR_CONST:
806 case BWRITERSPR_ADDR:
807 case BWRITERSPR_CONSTINT:
808 case BWRITERSPR_CONSTBOOL:
809 case BWRITERSPR_LABEL:
810 d3d9reg = d3d9_register(reg->type);
811 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
812 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
813 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
816 case BWRITERSPR_LOOP:
817 if(reg->regnum != 0) {
818 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
819 This->state = E_INVALIDARG;
822 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
823 token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
824 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
827 case BWRITERSPR_PREDICATE:
828 if(This->version != BWRITERVS_VERSION(2, 1)){
829 WARN("Predicate register is allowed only in vs_2_x\n");
830 This->state = E_INVALIDARG;
833 if(reg->regnum > 0) {
834 WARN("Only predicate register 0 is supported\n");
835 This->state = E_INVALIDARG;
838 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
839 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
840 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
845 WARN("Invalid register type for 2.0 vshader\n");
846 This->state = E_INVALIDARG;
850 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
852 token |= d3d9_srcmod(reg->srcmod);
855 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
857 put_dword(buffer, token);
859 /* vs_2_0 and newer write the register containing the index explicitly in the
862 if(token & D3DVS_ADDRMODE_RELATIVE)
863 vs_2_srcreg(This, reg->rel_reg, buffer);
866 static void sm_2_opcode(struct bc_writer *This,
867 const struct instruction *instr,
868 DWORD token, struct bytecode_buffer *buffer) {
869 /* From sm 2 onwards instruction length is encoded in the opcode field */
870 int dsts = instr->has_dst ? 1 : 0;
871 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
873 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
874 if(instr->has_predicate)
875 token |= D3DSHADER_INSTRUCTION_PREDICATED;
876 put_dword(buffer,token);
879 static const struct instr_handler_table vs_2_0_handlers[] = {
880 {BWRITERSIO_ADD, instr_handler},
881 {BWRITERSIO_NOP, instr_handler},
882 {BWRITERSIO_MOV, instr_handler},
883 {BWRITERSIO_SUB, instr_handler},
884 {BWRITERSIO_MAD, instr_handler},
885 {BWRITERSIO_MUL, instr_handler},
886 {BWRITERSIO_RCP, instr_handler},
887 {BWRITERSIO_RSQ, instr_handler},
888 {BWRITERSIO_DP3, instr_handler},
889 {BWRITERSIO_DP4, instr_handler},
890 {BWRITERSIO_MIN, instr_handler},
891 {BWRITERSIO_MAX, instr_handler},
892 {BWRITERSIO_SLT, instr_handler},
893 {BWRITERSIO_SGE, instr_handler},
894 {BWRITERSIO_ABS, instr_handler},
895 {BWRITERSIO_EXP, instr_handler},
896 {BWRITERSIO_LOG, instr_handler},
897 {BWRITERSIO_EXPP, instr_handler},
898 {BWRITERSIO_LOGP, instr_handler},
899 {BWRITERSIO_DST, instr_handler},
900 {BWRITERSIO_LRP, instr_handler},
901 {BWRITERSIO_FRC, instr_handler},
902 {BWRITERSIO_CRS, instr_handler},
903 {BWRITERSIO_SGN, instr_handler},
904 {BWRITERSIO_NRM, instr_handler},
905 {BWRITERSIO_SINCOS, instr_handler},
906 {BWRITERSIO_M4x4, instr_handler},
907 {BWRITERSIO_M4x3, instr_handler},
908 {BWRITERSIO_M3x4, instr_handler},
909 {BWRITERSIO_M3x3, instr_handler},
910 {BWRITERSIO_M3x2, instr_handler},
911 {BWRITERSIO_LIT, instr_handler},
912 {BWRITERSIO_POW, instr_handler},
913 {BWRITERSIO_MOVA, instr_handler},
915 {BWRITERSIO_CALL, instr_handler},
916 {BWRITERSIO_CALLNZ, instr_handler},
917 {BWRITERSIO_REP, instr_handler},
918 {BWRITERSIO_ENDREP, instr_handler},
919 {BWRITERSIO_IF, instr_handler},
920 {BWRITERSIO_LABEL, instr_handler},
921 {BWRITERSIO_ELSE, instr_handler},
922 {BWRITERSIO_ENDIF, instr_handler},
923 {BWRITERSIO_LOOP, instr_handler},
924 {BWRITERSIO_RET, instr_handler},
925 {BWRITERSIO_ENDLOOP, instr_handler},
927 {BWRITERSIO_END, NULL},
930 static const struct bytecode_backend vs_2_0_backend = {
939 static const struct instr_handler_table vs_2_x_handlers[] = {
940 {BWRITERSIO_ADD, instr_handler},
941 {BWRITERSIO_NOP, instr_handler},
942 {BWRITERSIO_MOV, instr_handler},
943 {BWRITERSIO_SUB, instr_handler},
944 {BWRITERSIO_MAD, instr_handler},
945 {BWRITERSIO_MUL, instr_handler},
946 {BWRITERSIO_RCP, instr_handler},
947 {BWRITERSIO_RSQ, instr_handler},
948 {BWRITERSIO_DP3, instr_handler},
949 {BWRITERSIO_DP4, instr_handler},
950 {BWRITERSIO_MIN, instr_handler},
951 {BWRITERSIO_MAX, instr_handler},
952 {BWRITERSIO_SLT, instr_handler},
953 {BWRITERSIO_SGE, instr_handler},
954 {BWRITERSIO_ABS, instr_handler},
955 {BWRITERSIO_EXP, instr_handler},
956 {BWRITERSIO_LOG, instr_handler},
957 {BWRITERSIO_EXPP, instr_handler},
958 {BWRITERSIO_LOGP, instr_handler},
959 {BWRITERSIO_DST, instr_handler},
960 {BWRITERSIO_LRP, instr_handler},
961 {BWRITERSIO_FRC, instr_handler},
962 {BWRITERSIO_CRS, instr_handler},
963 {BWRITERSIO_SGN, instr_handler},
964 {BWRITERSIO_NRM, instr_handler},
965 {BWRITERSIO_SINCOS, instr_handler},
966 {BWRITERSIO_M4x4, instr_handler},
967 {BWRITERSIO_M4x3, instr_handler},
968 {BWRITERSIO_M3x4, instr_handler},
969 {BWRITERSIO_M3x3, instr_handler},
970 {BWRITERSIO_M3x2, instr_handler},
971 {BWRITERSIO_LIT, instr_handler},
972 {BWRITERSIO_POW, instr_handler},
973 {BWRITERSIO_MOVA, instr_handler},
975 {BWRITERSIO_CALL, instr_handler},
976 {BWRITERSIO_CALLNZ, instr_handler},
977 {BWRITERSIO_REP, instr_handler},
978 {BWRITERSIO_ENDREP, instr_handler},
979 {BWRITERSIO_IF, instr_handler},
980 {BWRITERSIO_LABEL, instr_handler},
981 {BWRITERSIO_IFC, instr_handler},
982 {BWRITERSIO_ELSE, instr_handler},
983 {BWRITERSIO_ENDIF, instr_handler},
984 {BWRITERSIO_BREAK, instr_handler},
985 {BWRITERSIO_BREAKC, instr_handler},
986 {BWRITERSIO_LOOP, instr_handler},
987 {BWRITERSIO_RET, instr_handler},
988 {BWRITERSIO_ENDLOOP, instr_handler},
990 {BWRITERSIO_SETP, instr_handler},
991 {BWRITERSIO_BREAKP, instr_handler},
993 {BWRITERSIO_END, NULL},
996 static const struct bytecode_backend vs_2_x_backend = {
1005 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1007 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1009 const DWORD reg = (1<<31) |
1010 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
1011 ((D3DSPR_SAMPLER << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
1012 D3DSP_WRITEMASK_ALL;
1014 for(i = 0; i < shader->num_samplers; i++) {
1015 /* Write the DCL instruction */
1016 put_dword(buffer, instr_dcl);
1018 /* Already shifted */
1019 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
1020 put_dword(buffer, token);
1021 put_dword(buffer, reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK));
1025 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1026 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1032 /* Declare the shader type and version */
1033 put_dword(buffer, This->version);
1034 write_samplers(shader, buffer);
1035 write_constF(shader, buffer, TRUE);
1036 write_constB(shader, buffer, TRUE);
1037 write_constI(shader, buffer, TRUE);
1040 static void ps_2_srcreg(struct bc_writer *This,
1041 const struct shader_reg *reg,
1042 struct bytecode_buffer *buffer) {
1043 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1046 WARN("Relative addressing not supported in <= ps_3_0\n");
1047 This->state = E_INVALIDARG;
1052 case BWRITERSPR_INPUT:
1053 token |= map_ps_input(This, reg);
1056 /* Can be mapped 1:1 */
1057 case BWRITERSPR_TEMP:
1058 case BWRITERSPR_CONST:
1059 case BWRITERSPR_COLOROUT:
1060 case BWRITERSPR_CONSTBOOL:
1061 case BWRITERSPR_CONSTINT:
1062 case BWRITERSPR_SAMPLER:
1063 case BWRITERSPR_LABEL:
1064 case BWRITERSPR_DEPTHOUT:
1065 d3d9reg = d3d9_register(reg->type);
1066 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1067 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1068 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1071 case BWRITERSPR_PREDICATE:
1072 if(This->version != BWRITERPS_VERSION(2, 1)){
1073 WARN("Predicate register not supported in ps_2_0\n");
1074 This->state = E_INVALIDARG;
1077 WARN("Predicate register with regnum %u not supported\n",
1079 This->state = E_INVALIDARG;
1081 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1082 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1083 token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
1087 WARN("Invalid register type for ps_2_0 shader\n");
1088 This->state = E_INVALIDARG;
1092 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1094 token |= d3d9_srcmod(reg->srcmod);
1095 put_dword(buffer, token);
1098 static void ps_2_0_dstreg(struct bc_writer *This,
1099 const struct shader_reg *reg,
1100 struct bytecode_buffer *buffer,
1101 DWORD shift, DWORD mod) {
1102 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1106 WARN("Relative addressing not supported for destination registers\n");
1107 This->state = E_INVALIDARG;
1112 case BWRITERSPR_TEMP: /* 1:1 mapping */
1113 case BWRITERSPR_COLOROUT:
1114 case BWRITERSPR_DEPTHOUT:
1115 d3d9reg = d3d9_register(reg->type);
1116 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1117 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1118 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1121 case BWRITERSPR_PREDICATE:
1122 if(This->version != BWRITERPS_VERSION(2, 1)){
1123 WARN("Predicate register not supported in ps_2_0\n");
1124 This->state = E_INVALIDARG;
1126 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1127 token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1128 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1131 /* texkill uses the input register as a destination parameter */
1132 case BWRITERSPR_INPUT:
1133 token |= map_ps_input(This, reg);
1137 WARN("Invalid dest register type for 2.x pshader\n");
1138 This->state = E_INVALIDARG;
1142 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1143 token |= d3d9_dstmod(mod);
1145 token |= d3d9_writemask(reg->writemask);
1146 put_dword(buffer, token);
1149 static const struct instr_handler_table ps_2_0_handlers[] = {
1150 {BWRITERSIO_ADD, instr_handler},
1151 {BWRITERSIO_NOP, instr_handler},
1152 {BWRITERSIO_MOV, instr_handler},
1153 {BWRITERSIO_SUB, instr_handler},
1154 {BWRITERSIO_MAD, instr_handler},
1155 {BWRITERSIO_MUL, instr_handler},
1156 {BWRITERSIO_RCP, instr_handler},
1157 {BWRITERSIO_RSQ, instr_handler},
1158 {BWRITERSIO_DP3, instr_handler},
1159 {BWRITERSIO_DP4, instr_handler},
1160 {BWRITERSIO_MIN, instr_handler},
1161 {BWRITERSIO_MAX, instr_handler},
1162 {BWRITERSIO_ABS, instr_handler},
1163 {BWRITERSIO_EXP, instr_handler},
1164 {BWRITERSIO_LOG, instr_handler},
1165 {BWRITERSIO_EXPP, instr_handler},
1166 {BWRITERSIO_LOGP, instr_handler},
1167 {BWRITERSIO_LRP, instr_handler},
1168 {BWRITERSIO_FRC, instr_handler},
1169 {BWRITERSIO_CRS, instr_handler},
1170 {BWRITERSIO_NRM, instr_handler},
1171 {BWRITERSIO_SINCOS, instr_handler},
1172 {BWRITERSIO_M4x4, instr_handler},
1173 {BWRITERSIO_M4x3, instr_handler},
1174 {BWRITERSIO_M3x4, instr_handler},
1175 {BWRITERSIO_M3x3, instr_handler},
1176 {BWRITERSIO_M3x2, instr_handler},
1177 {BWRITERSIO_POW, instr_handler},
1178 {BWRITERSIO_DP2ADD, instr_handler},
1179 {BWRITERSIO_CMP, instr_handler},
1181 {BWRITERSIO_TEX, instr_handler},
1182 {BWRITERSIO_TEXLDP, instr_handler},
1183 {BWRITERSIO_TEXLDB, instr_handler},
1184 {BWRITERSIO_TEXKILL, instr_handler},
1186 {BWRITERSIO_END, NULL},
1189 static const struct bytecode_backend ps_2_0_backend = {
1198 static const struct instr_handler_table ps_2_x_handlers[] = {
1199 {BWRITERSIO_ADD, instr_handler},
1200 {BWRITERSIO_NOP, instr_handler},
1201 {BWRITERSIO_MOV, instr_handler},
1202 {BWRITERSIO_SUB, instr_handler},
1203 {BWRITERSIO_MAD, instr_handler},
1204 {BWRITERSIO_MUL, instr_handler},
1205 {BWRITERSIO_RCP, instr_handler},
1206 {BWRITERSIO_RSQ, instr_handler},
1207 {BWRITERSIO_DP3, instr_handler},
1208 {BWRITERSIO_DP4, instr_handler},
1209 {BWRITERSIO_MIN, instr_handler},
1210 {BWRITERSIO_MAX, instr_handler},
1211 {BWRITERSIO_ABS, instr_handler},
1212 {BWRITERSIO_EXP, instr_handler},
1213 {BWRITERSIO_LOG, instr_handler},
1214 {BWRITERSIO_EXPP, instr_handler},
1215 {BWRITERSIO_LOGP, instr_handler},
1216 {BWRITERSIO_LRP, instr_handler},
1217 {BWRITERSIO_FRC, instr_handler},
1218 {BWRITERSIO_CRS, instr_handler},
1219 {BWRITERSIO_NRM, instr_handler},
1220 {BWRITERSIO_SINCOS, instr_handler},
1221 {BWRITERSIO_M4x4, instr_handler},
1222 {BWRITERSIO_M4x3, instr_handler},
1223 {BWRITERSIO_M3x4, instr_handler},
1224 {BWRITERSIO_M3x3, instr_handler},
1225 {BWRITERSIO_M3x2, instr_handler},
1226 {BWRITERSIO_POW, instr_handler},
1227 {BWRITERSIO_DP2ADD, instr_handler},
1228 {BWRITERSIO_CMP, instr_handler},
1230 {BWRITERSIO_CALL, instr_handler},
1231 {BWRITERSIO_CALLNZ, instr_handler},
1232 {BWRITERSIO_REP, instr_handler},
1233 {BWRITERSIO_ENDREP, instr_handler},
1234 {BWRITERSIO_IF, instr_handler},
1235 {BWRITERSIO_LABEL, instr_handler},
1236 {BWRITERSIO_IFC, instr_handler},
1237 {BWRITERSIO_ELSE, instr_handler},
1238 {BWRITERSIO_ENDIF, instr_handler},
1239 {BWRITERSIO_BREAK, instr_handler},
1240 {BWRITERSIO_BREAKC, instr_handler},
1241 {BWRITERSIO_RET, instr_handler},
1243 {BWRITERSIO_TEX, instr_handler},
1244 {BWRITERSIO_TEXLDP, instr_handler},
1245 {BWRITERSIO_TEXLDB, instr_handler},
1246 {BWRITERSIO_TEXKILL, instr_handler},
1247 {BWRITERSIO_DSX, instr_handler},
1248 {BWRITERSIO_DSY, instr_handler},
1250 {BWRITERSIO_SETP, instr_handler},
1251 {BWRITERSIO_BREAKP, instr_handler},
1253 {BWRITERSIO_TEXLDD, instr_handler},
1255 {BWRITERSIO_END, NULL},
1258 static const struct bytecode_backend ps_2_x_backend = {
1267 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1268 /* Declare the shader type and version */
1269 put_dword(buffer, This->version);
1271 write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
1272 write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT);
1273 write_constF(shader, buffer, TRUE);
1274 write_constB(shader, buffer, TRUE);
1275 write_constI(shader, buffer, TRUE);
1276 write_samplers(shader, buffer);
1280 static void sm_3_srcreg(struct bc_writer *This,
1281 const struct shader_reg *reg,
1282 struct bytecode_buffer *buffer) {
1283 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1286 d3d9reg = d3d9_register(reg->type);
1287 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1288 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1289 token |= reg->regnum & D3DSP_REGNUM_MASK;
1291 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
1292 token |= d3d9_srcmod(reg->srcmod);
1295 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
1296 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
1297 This->state = E_INVALIDARG;
1300 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
1301 reg->rel_reg->type == BWRITERSPR_LOOP) &&
1302 reg->rel_reg->regnum == 0) {
1303 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1305 WARN("Unsupported relative addressing register\n");
1306 This->state = E_INVALIDARG;
1311 put_dword(buffer, token);
1313 /* vs_2_0 and newer write the register containing the index explicitly in the
1316 if(token & D3DVS_ADDRMODE_RELATIVE) {
1317 sm_3_srcreg(This, reg->rel_reg, buffer);
1321 static void sm_3_dstreg(struct bc_writer *This,
1322 const struct shader_reg *reg,
1323 struct bytecode_buffer *buffer,
1324 DWORD shift, DWORD mod) {
1325 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
1329 if(This->version == BWRITERVS_VERSION(3, 0) &&
1330 reg->type == BWRITERSPR_OUTPUT) {
1331 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1333 WARN("Relative addressing not supported for this shader type or register type\n");
1334 This->state = E_INVALIDARG;
1339 d3d9reg = d3d9_register(reg->type);
1340 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
1341 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
1342 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
1344 token |= d3d9_dstmod(mod);
1346 token |= d3d9_writemask(reg->writemask);
1347 put_dword(buffer, token);
1349 /* vs_2_0 and newer write the register containing the index explicitly in the
1352 if(token & D3DVS_ADDRMODE_RELATIVE) {
1353 sm_3_srcreg(This, reg->rel_reg, buffer);
1357 static const struct instr_handler_table vs_3_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_SLT, instr_handler},
1371 {BWRITERSIO_SGE, instr_handler},
1372 {BWRITERSIO_ABS, instr_handler},
1373 {BWRITERSIO_EXP, instr_handler},
1374 {BWRITERSIO_LOG, instr_handler},
1375 {BWRITERSIO_EXPP, instr_handler},
1376 {BWRITERSIO_LOGP, instr_handler},
1377 {BWRITERSIO_DST, instr_handler},
1378 {BWRITERSIO_LRP, instr_handler},
1379 {BWRITERSIO_FRC, instr_handler},
1380 {BWRITERSIO_CRS, instr_handler},
1381 {BWRITERSIO_SGN, instr_handler},
1382 {BWRITERSIO_NRM, instr_handler},
1383 {BWRITERSIO_SINCOS, instr_handler},
1384 {BWRITERSIO_M4x4, instr_handler},
1385 {BWRITERSIO_M4x3, instr_handler},
1386 {BWRITERSIO_M3x4, instr_handler},
1387 {BWRITERSIO_M3x3, instr_handler},
1388 {BWRITERSIO_M3x2, instr_handler},
1389 {BWRITERSIO_LIT, instr_handler},
1390 {BWRITERSIO_POW, instr_handler},
1391 {BWRITERSIO_MOVA, instr_handler},
1393 {BWRITERSIO_CALL, instr_handler},
1394 {BWRITERSIO_CALLNZ, instr_handler},
1395 {BWRITERSIO_REP, instr_handler},
1396 {BWRITERSIO_ENDREP, instr_handler},
1397 {BWRITERSIO_IF, instr_handler},
1398 {BWRITERSIO_LABEL, instr_handler},
1399 {BWRITERSIO_IFC, instr_handler},
1400 {BWRITERSIO_ELSE, instr_handler},
1401 {BWRITERSIO_ENDIF, instr_handler},
1402 {BWRITERSIO_BREAK, instr_handler},
1403 {BWRITERSIO_BREAKC, instr_handler},
1404 {BWRITERSIO_LOOP, instr_handler},
1405 {BWRITERSIO_RET, instr_handler},
1406 {BWRITERSIO_ENDLOOP, instr_handler},
1408 {BWRITERSIO_SETP, instr_handler},
1409 {BWRITERSIO_BREAKP, instr_handler},
1410 {BWRITERSIO_TEXLDL, instr_handler},
1412 {BWRITERSIO_END, NULL},
1415 static const struct bytecode_backend vs_3_backend = {
1424 static const struct instr_handler_table ps_3_handlers[] = {
1425 {BWRITERSIO_ADD, instr_handler},
1426 {BWRITERSIO_NOP, instr_handler},
1427 {BWRITERSIO_MOV, instr_handler},
1428 {BWRITERSIO_SUB, instr_handler},
1429 {BWRITERSIO_MAD, instr_handler},
1430 {BWRITERSIO_MUL, instr_handler},
1431 {BWRITERSIO_RCP, instr_handler},
1432 {BWRITERSIO_RSQ, instr_handler},
1433 {BWRITERSIO_DP3, instr_handler},
1434 {BWRITERSIO_DP4, instr_handler},
1435 {BWRITERSIO_MIN, instr_handler},
1436 {BWRITERSIO_MAX, instr_handler},
1437 {BWRITERSIO_ABS, instr_handler},
1438 {BWRITERSIO_EXP, instr_handler},
1439 {BWRITERSIO_LOG, instr_handler},
1440 {BWRITERSIO_EXPP, instr_handler},
1441 {BWRITERSIO_LOGP, instr_handler},
1442 {BWRITERSIO_LRP, instr_handler},
1443 {BWRITERSIO_FRC, instr_handler},
1444 {BWRITERSIO_CRS, instr_handler},
1445 {BWRITERSIO_NRM, instr_handler},
1446 {BWRITERSIO_SINCOS, instr_handler},
1447 {BWRITERSIO_M4x4, instr_handler},
1448 {BWRITERSIO_M4x3, instr_handler},
1449 {BWRITERSIO_M3x4, instr_handler},
1450 {BWRITERSIO_M3x3, instr_handler},
1451 {BWRITERSIO_M3x2, instr_handler},
1452 {BWRITERSIO_POW, instr_handler},
1453 {BWRITERSIO_DP2ADD, instr_handler},
1454 {BWRITERSIO_CMP, instr_handler},
1456 {BWRITERSIO_CALL, instr_handler},
1457 {BWRITERSIO_CALLNZ, instr_handler},
1458 {BWRITERSIO_REP, instr_handler},
1459 {BWRITERSIO_ENDREP, instr_handler},
1460 {BWRITERSIO_IF, instr_handler},
1461 {BWRITERSIO_LABEL, instr_handler},
1462 {BWRITERSIO_IFC, instr_handler},
1463 {BWRITERSIO_ELSE, instr_handler},
1464 {BWRITERSIO_ENDIF, instr_handler},
1465 {BWRITERSIO_BREAK, instr_handler},
1466 {BWRITERSIO_BREAKC, instr_handler},
1467 {BWRITERSIO_LOOP, instr_handler},
1468 {BWRITERSIO_RET, instr_handler},
1469 {BWRITERSIO_ENDLOOP, instr_handler},
1471 {BWRITERSIO_SETP, instr_handler},
1472 {BWRITERSIO_BREAKP, instr_handler},
1473 {BWRITERSIO_TEXLDL, instr_handler},
1475 {BWRITERSIO_TEX, instr_handler},
1476 {BWRITERSIO_TEXLDP, instr_handler},
1477 {BWRITERSIO_TEXLDB, instr_handler},
1478 {BWRITERSIO_TEXKILL, instr_handler},
1479 {BWRITERSIO_DSX, instr_handler},
1480 {BWRITERSIO_DSY, instr_handler},
1481 {BWRITERSIO_TEXLDD, instr_handler},
1483 {BWRITERSIO_END, NULL},
1486 static const struct bytecode_backend ps_3_backend = {
1495 static void init_vs20_dx9_writer(struct bc_writer *writer) {
1496 TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
1497 writer->funcs = &vs_2_0_backend;
1500 static void init_vs2x_dx9_writer(struct bc_writer *writer) {
1501 TRACE("Creating DirectX9 vertex shader 2.x writer\n");
1502 writer->funcs = &vs_2_x_backend;
1505 static void init_vs30_dx9_writer(struct bc_writer *writer) {
1506 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
1507 writer->funcs = &vs_3_backend;
1510 static void init_ps20_dx9_writer(struct bc_writer *writer) {
1511 TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
1512 writer->funcs = &ps_2_0_backend;
1515 static void init_ps2x_dx9_writer(struct bc_writer *writer) {
1516 TRACE("Creating DirectX9 pixel shader 2.x writer\n");
1517 writer->funcs = &ps_2_x_backend;
1520 static void init_ps30_dx9_writer(struct bc_writer *writer) {
1521 TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
1522 writer->funcs = &ps_3_backend;
1525 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
1526 struct bc_writer *ret = asm_alloc(sizeof(*ret));
1529 WARN("Failed to allocate a bytecode writer instance\n");
1534 case BWRITERVS_VERSION(1, 0):
1535 if(dxversion != 9) {
1536 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
1539 /* TODO: Set the appropriate writer backend */
1541 case BWRITERVS_VERSION(1, 1):
1542 if(dxversion != 9) {
1543 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
1546 /* TODO: Set the appropriate writer backend */
1548 case BWRITERVS_VERSION(2, 0):
1549 if(dxversion != 9) {
1550 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
1553 init_vs20_dx9_writer(ret);
1555 case BWRITERVS_VERSION(2, 1):
1556 if(dxversion != 9) {
1557 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
1560 init_vs2x_dx9_writer(ret);
1562 case BWRITERVS_VERSION(3, 0):
1563 if(dxversion != 9) {
1564 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
1567 init_vs30_dx9_writer(ret);
1570 case BWRITERPS_VERSION(1, 0):
1571 if(dxversion != 9) {
1572 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
1575 /* TODO: Set the appropriate writer backend */
1577 case BWRITERPS_VERSION(1, 1):
1578 if(dxversion != 9) {
1579 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
1582 /* TODO: Set the appropriate writer backend */
1584 case BWRITERPS_VERSION(1, 2):
1585 if(dxversion != 9) {
1586 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
1589 /* TODO: Set the appropriate writer backend */
1591 case BWRITERPS_VERSION(1, 3):
1592 if(dxversion != 9) {
1593 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
1596 /* TODO: Set the appropriate writer backend */
1598 case BWRITERPS_VERSION(1, 4):
1599 if(dxversion != 9) {
1600 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
1603 /* TODO: Set the appropriate writer backend */
1606 case BWRITERPS_VERSION(2, 0):
1607 if(dxversion != 9) {
1608 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
1611 init_ps20_dx9_writer(ret);
1614 case BWRITERPS_VERSION(2, 1):
1615 if(dxversion != 9) {
1616 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
1619 init_ps2x_dx9_writer(ret);
1622 case BWRITERPS_VERSION(3, 0):
1623 if(dxversion != 9) {
1624 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
1627 init_ps30_dx9_writer(ret);
1631 WARN("Unexpected shader version requested: %08x\n", version);
1634 ret->version = version;
1642 static HRESULT call_instr_handler(struct bc_writer *writer,
1643 const struct instruction *instr,
1644 struct bytecode_buffer *buffer) {
1647 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
1648 if(instr->opcode == writer->funcs->instructions[i].opcode) {
1649 if(!writer->funcs->instructions[i].func) {
1650 WARN("Opcode %u not supported by this profile\n", instr->opcode);
1651 return E_INVALIDARG;
1653 writer->funcs->instructions[i].func(writer, instr, buffer);
1659 FIXME("Unhandled instruction %u\n", instr->opcode);
1660 return E_INVALIDARG;
1663 /* SlWriteBytecode (wineshader.@)
1665 * Writes shader version specific bytecode from the shader passed in.
1666 * The returned bytecode can be passed to the Direct3D runtime like
1667 * IDirect3DDevice9::Create*Shader.
1670 * shader: Shader to translate into bytecode
1671 * version: Shader version to generate(d3d version token)
1672 * dxversion: DirectX version the code targets
1673 * result: the resulting shader bytecode
1678 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
1679 struct bc_writer *writer;
1680 struct bytecode_buffer *buffer = NULL;
1685 ERR("NULL shader structure, aborting\n");
1688 writer = create_writer(shader->version, dxversion);
1692 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
1693 WARN("or out of memory\n");
1698 buffer = allocate_buffer();
1700 WARN("Failed to allocate a buffer for the shader bytecode\n");
1705 writer->funcs->header(writer, shader, buffer);
1706 if(FAILED(writer->state)) {
1711 for(i = 0; i < shader->num_instrs; i++) {
1712 hr = call_instr_handler(writer, shader->instr[i], buffer);
1718 if(FAILED(writer->state)) {
1723 writer->funcs->end(writer, shader, buffer);
1725 if(FAILED(buffer->state)) {
1730 /* Cut off unneeded memory from the result buffer */
1731 *result = asm_realloc(buffer->data,
1732 sizeof(DWORD) * buffer->size);
1734 *result = buffer->data;
1736 buffer->data = NULL;
1741 asm_free(buffer->data);
1748 void SlDeleteShader(struct bwriter_shader *shader) {
1751 TRACE("Deleting shader %p\n", shader);
1753 for(i = 0; i < shader->num_cf; i++) {
1754 asm_free(shader->constF[i]);
1756 asm_free(shader->constF);
1757 for(i = 0; i < shader->num_ci; i++) {
1758 asm_free(shader->constI[i]);
1760 asm_free(shader->constI);
1761 for(i = 0; i < shader->num_cb; i++) {
1762 asm_free(shader->constB[i]);
1764 asm_free(shader->constB);
1766 asm_free(shader->inputs);
1767 asm_free(shader->outputs);
1768 asm_free(shader->samplers);
1770 for(i = 0; i < shader->num_instrs; i++) {
1771 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
1772 asm_free(shader->instr[i]->src[j].rel_reg);
1774 asm_free(shader->instr[i]->src);
1775 asm_free(shader->instr[i]);
1777 asm_free(shader->instr);