winex11: Remove now unnecessary surface wrapper struct.
[wine.git] / dlls / d3dcompiler_43 / bytecodewriter.c
blob35f539350cd1af219c90f6f9aae431f03c16d08e
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 "wine/debug.h"
25 #include "d3d9types.h"
26 #include "d3dcompiler_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(bytecodewriter);
30 static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size)
32 unsigned int max_capacity, new_capacity;
33 void *new_elements;
35 if (count <= *capacity)
36 return TRUE;
38 max_capacity = ~0u / size;
39 if (count > max_capacity)
40 return FALSE;
42 new_capacity = max(8, *capacity);
43 while (new_capacity < count && new_capacity <= max_capacity / 2)
44 new_capacity *= 2;
45 if (new_capacity < count)
46 new_capacity = count;
48 if (!(new_elements = realloc(*elements, new_capacity * size)))
50 ERR("Failed to allocate memory.\n");
51 return FALSE;
54 *elements = new_elements;
55 *capacity = new_capacity;
56 return TRUE;
59 /****************************************************************
60 * General assembler shader construction helper routines follow *
61 ****************************************************************/
62 /* struct instruction *alloc_instr
64 * Allocates a new instruction structure with srcs registers
66 * Parameters:
67 * srcs: Number of source registers to allocate
69 * Returns:
70 * A pointer to the allocated instruction structure
71 * NULL in case of an allocation failure
73 struct instruction *alloc_instr(unsigned int srcs) {
74 struct instruction *ret = calloc(1, sizeof(*ret));
75 if(!ret) {
76 ERR("Failed to allocate memory for an instruction structure\n");
77 return NULL;
80 if(srcs) {
81 ret->src = calloc(1, srcs * sizeof(*ret->src));
82 if(!ret->src) {
83 ERR("Failed to allocate memory for instruction registers\n");
84 free(ret);
85 return NULL;
87 ret->num_srcs = srcs;
89 return ret;
92 /* void add_instruction
94 * Adds a new instruction to the shader's instructions array and grows the instruction array
95 * if needed.
97 * The function does NOT copy the instruction structure. Make sure not to release the
98 * instruction or any of its substructures like registers.
100 * Parameters:
101 * shader: Shader to add the instruction to
102 * instr: Instruction to add to the shader
104 BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr) {
105 if(!shader) return FALSE;
107 if (!array_reserve((void **)&shader->instr, &shader->instr_alloc_size,
108 shader->num_instrs + 1, sizeof(*shader->instr)))
109 return FALSE;
111 shader->instr[shader->num_instrs] = instr;
112 shader->num_instrs++;
113 return TRUE;
116 BOOL add_constF(struct bwriter_shader *shader, uint32_t reg, float x, float y, float z, float w)
118 struct constant *newconst;
120 if (shader->num_cf)
122 struct constant **newarray;
123 newarray = realloc(shader->constF, sizeof(*shader->constF) * (shader->num_cf + 1));
124 if (!newarray)
126 ERR("Failed to grow the constants array\n");
127 return FALSE;
129 shader->constF = newarray;
131 else
133 shader->constF = calloc(1, sizeof(*shader->constF));
134 if (!shader->constF)
136 ERR("Failed to allocate the constants array\n");
137 return FALSE;
141 newconst = calloc(1, sizeof(*newconst));
142 if (!newconst)
144 ERR("Failed to allocate a new constant\n");
145 return FALSE;
147 newconst->regnum = reg;
148 newconst->value[0].f = x;
149 newconst->value[1].f = y;
150 newconst->value[2].f = z;
151 newconst->value[3].f = w;
152 shader->constF[shader->num_cf] = newconst;
154 shader->num_cf++;
155 return TRUE;
158 BOOL add_constI(struct bwriter_shader *shader, uint32_t reg, int x, int y, int z, int w)
160 struct constant *newconst;
162 if (shader->num_ci)
164 struct constant **newarray;
165 newarray = realloc(shader->constI, sizeof(*shader->constI) * (shader->num_ci + 1));
166 if (!newarray)
168 ERR("Failed to grow the constants array\n");
169 return FALSE;
171 shader->constI = newarray;
173 else
175 shader->constI = calloc(1, sizeof(*shader->constI));
176 if (!shader->constI)
178 ERR("Failed to allocate the constants array\n");
179 return FALSE;
183 newconst = calloc(1, sizeof(*newconst));
184 if (!newconst)
186 ERR("Failed to allocate a new constant\n");
187 return FALSE;
189 newconst->regnum = reg;
190 newconst->value[0].i = x;
191 newconst->value[1].i = y;
192 newconst->value[2].i = z;
193 newconst->value[3].i = w;
194 shader->constI[shader->num_ci] = newconst;
196 shader->num_ci++;
197 return TRUE;
200 BOOL add_constB(struct bwriter_shader *shader, uint32_t reg, BOOL x)
202 struct constant *newconst;
204 if (shader->num_cb)
206 struct constant **newarray;
207 newarray = realloc(shader->constB, sizeof(*shader->constB) * (shader->num_cb + 1));
208 if (!newarray)
210 ERR("Failed to grow the constants array\n");
211 return FALSE;
213 shader->constB = newarray;
215 else
217 shader->constB = calloc(1, sizeof(*shader->constB));
218 if (!shader->constB)
220 ERR("Failed to allocate the constants array\n");
221 return FALSE;
225 newconst = calloc(1, sizeof(*newconst));
226 if (!newconst)
228 ERR("Failed to allocate a new constant\n");
229 return FALSE;
231 newconst->regnum = reg;
232 newconst->value[0].b = x;
233 shader->constB[shader->num_cb] = newconst;
235 shader->num_cb++;
236 return TRUE;
239 BOOL record_declaration(struct bwriter_shader *shader, uint32_t usage, uint32_t usage_idx,
240 uint32_t mod, BOOL output, uint32_t regnum, uint32_t writemask, BOOL builtin)
242 struct declaration **decl;
243 unsigned int i, *num;
245 if (!shader)
246 return FALSE;
248 if (output)
250 num = &shader->num_outputs;
251 decl = &shader->outputs;
253 else
255 num = &shader->num_inputs;
256 decl = &shader->inputs;
259 if (*num == 0)
261 *decl = calloc(1, sizeof(**decl));
262 if (!*decl)
264 ERR("Error allocating declarations array\n");
265 return FALSE;
268 else
270 struct declaration *newdecl;
272 for (i = 0; i < *num; i++)
274 if ((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask))
275 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
276 regnum, (*decl)[i].writemask & writemask);
279 newdecl = realloc(*decl, sizeof(**decl) * ((*num) + 1));
280 if (!newdecl)
282 ERR("Error reallocating declarations array\n");
283 return FALSE;
285 *decl = newdecl;
287 (*decl)[*num].usage = usage;
288 (*decl)[*num].usage_idx = usage_idx;
289 (*decl)[*num].regnum = regnum;
290 (*decl)[*num].mod = mod;
291 (*decl)[*num].writemask = writemask;
292 (*decl)[*num].builtin = builtin;
293 (*num)++;
295 return TRUE;
298 BOOL record_sampler(struct bwriter_shader *shader, uint32_t samptype, uint32_t mod, uint32_t regnum) {
299 unsigned int i;
301 if (!shader)
302 return FALSE;
304 if (shader->num_samplers == 0)
306 shader->samplers = calloc(1, sizeof(*shader->samplers));
307 if (!shader->samplers)
309 ERR("Error allocating samplers array\n");
310 return FALSE;
313 else
315 struct samplerdecl *newarray;
317 for (i = 0; i < shader->num_samplers; i++)
319 if (shader->samplers[i].regnum == regnum)
321 WARN("Sampler %u already declared\n", regnum);
322 /* This is not an error as far as the assembler is concerned.
323 * Direct3D might refuse to load the compiled shader though */
327 newarray = realloc(shader->samplers, sizeof(*shader->samplers) * (shader->num_samplers + 1));
328 if (!newarray)
330 ERR("Error reallocating samplers array\n");
331 return FALSE;
333 shader->samplers = newarray;
336 shader->samplers[shader->num_samplers].type = samptype;
337 shader->samplers[shader->num_samplers].mod = mod;
338 shader->samplers[shader->num_samplers].regnum = regnum;
339 shader->num_samplers++;
340 return TRUE;
343 struct bytecode_buffer
345 uint32_t *data;
346 unsigned int size, alloc_size;
347 HRESULT state;
350 struct bc_writer;
352 typedef void (*instr_writer)(struct bc_writer *writer, const struct instruction *instr,
353 struct bytecode_buffer *buffer);
355 struct bytecode_backend
357 void (*header)(struct bc_writer *writer, const struct bwriter_shader *shader,
358 struct bytecode_buffer *buffer);
359 void (*end)(struct bc_writer *writer, const struct bwriter_shader *shader,
360 struct bytecode_buffer *buffer);
361 void (*srcreg)(struct bc_writer *writer, const struct shader_reg *reg,
362 struct bytecode_buffer *buffer);
363 void (*dstreg)(struct bc_writer *writer, const struct shader_reg *reg,
364 struct bytecode_buffer *buffer, uint32_t shift, uint32_t mod);
365 void (*opcode)(struct bc_writer *writer, const struct instruction *instr,
366 uint32_t token, struct bytecode_buffer *buffer);
368 const struct instr_handler_table
370 uint32_t opcode;
371 instr_writer func;
372 } *instructions;
375 struct bc_writer
377 const struct bytecode_backend *funcs;
378 const struct bwriter_shader *shader;
380 HRESULT state;
382 /* Vertex shader varying mapping. */
383 uint32_t oPos_regnum, oD_regnum[2], oT_regnum[8], oFog_regnum, oFog_mask, oPts_regnum, oPts_mask;
385 /* Pixel shader varying mapping. */
386 uint32_t t_regnum[8], v_regnum[2];
390 /* shader bytecode buffer manipulation functions.
391 * allocate_buffer creates a new buffer structure, put_u32 adds a new
392 * uint32_t to the buffer. In the rare case of a memory allocation failure
393 * when trying to grow the buffer a flag is set in the buffer to mark it
394 * invalid. This avoids return value checking and passing in many places
396 static struct bytecode_buffer *allocate_buffer(void) {
397 struct bytecode_buffer *ret;
399 ret = calloc(1, sizeof(*ret));
400 if(!ret) return NULL;
401 ret->state = S_OK;
402 return ret;
405 static void put_u32(struct bytecode_buffer *buffer, uint32_t value)
407 if (FAILED(buffer->state))
408 return;
410 if (!array_reserve((void **)&buffer->data, &buffer->alloc_size, buffer->size + 1, sizeof(*buffer->data)))
412 buffer->state = E_OUTOFMEMORY;
413 return;
416 buffer->data[buffer->size++] = value;
419 /* bwriter -> d3d9 conversion functions. */
421 static uint32_t sm1_version(const struct bwriter_shader *shader)
423 switch (shader->type)
425 case ST_VERTEX:
426 return D3DVS_VERSION(shader->major_version, shader->minor_version);
427 case ST_PIXEL:
428 return D3DPS_VERSION(shader->major_version, shader->minor_version);
429 default:
430 ERR("Invalid shader type %#x.\n", shader->type);
431 return 0;
435 static uint32_t d3d9_swizzle(uint32_t bwriter_swizzle)
437 uint32_t ret = 0;
439 if ((bwriter_swizzle & BWRITERVS_X_X) == BWRITERVS_X_X) ret |= D3DVS_X_X;
440 if ((bwriter_swizzle & BWRITERVS_X_Y) == BWRITERVS_X_Y) ret |= D3DVS_X_Y;
441 if ((bwriter_swizzle & BWRITERVS_X_Z) == BWRITERVS_X_Z) ret |= D3DVS_X_Z;
442 if ((bwriter_swizzle & BWRITERVS_X_W) == BWRITERVS_X_W) ret |= D3DVS_X_W;
444 if ((bwriter_swizzle & BWRITERVS_Y_X) == BWRITERVS_Y_X) ret |= D3DVS_Y_X;
445 if ((bwriter_swizzle & BWRITERVS_Y_Y) == BWRITERVS_Y_Y) ret |= D3DVS_Y_Y;
446 if ((bwriter_swizzle & BWRITERVS_Y_Z) == BWRITERVS_Y_Z) ret |= D3DVS_Y_Z;
447 if ((bwriter_swizzle & BWRITERVS_Y_W) == BWRITERVS_Y_W) ret |= D3DVS_Y_W;
449 if ((bwriter_swizzle & BWRITERVS_Z_X) == BWRITERVS_Z_X) ret |= D3DVS_Z_X;
450 if ((bwriter_swizzle & BWRITERVS_Z_Y) == BWRITERVS_Z_Y) ret |= D3DVS_Z_Y;
451 if ((bwriter_swizzle & BWRITERVS_Z_Z) == BWRITERVS_Z_Z) ret |= D3DVS_Z_Z;
452 if ((bwriter_swizzle & BWRITERVS_Z_W) == BWRITERVS_Z_W) ret |= D3DVS_Z_W;
454 if ((bwriter_swizzle & BWRITERVS_W_X) == BWRITERVS_W_X) ret |= D3DVS_W_X;
455 if ((bwriter_swizzle & BWRITERVS_W_Y) == BWRITERVS_W_Y) ret |= D3DVS_W_Y;
456 if ((bwriter_swizzle & BWRITERVS_W_Z) == BWRITERVS_W_Z) ret |= D3DVS_W_Z;
457 if ((bwriter_swizzle & BWRITERVS_W_W) == BWRITERVS_W_W) ret |= D3DVS_W_W;
459 return ret;
462 static uint32_t d3d9_writemask(uint32_t bwriter_writemask)
464 uint32_t ret = 0;
466 if (bwriter_writemask & BWRITERSP_WRITEMASK_0) ret |= D3DSP_WRITEMASK_0;
467 if (bwriter_writemask & BWRITERSP_WRITEMASK_1) ret |= D3DSP_WRITEMASK_1;
468 if (bwriter_writemask & BWRITERSP_WRITEMASK_2) ret |= D3DSP_WRITEMASK_2;
469 if (bwriter_writemask & BWRITERSP_WRITEMASK_3) ret |= D3DSP_WRITEMASK_3;
471 return ret;
474 static uint32_t d3d9_srcmod(uint32_t bwriter_srcmod)
476 switch (bwriter_srcmod)
478 case BWRITERSPSM_NONE: return D3DSPSM_NONE;
479 case BWRITERSPSM_NEG: return D3DSPSM_NEG;
480 case BWRITERSPSM_BIAS: return D3DSPSM_BIAS;
481 case BWRITERSPSM_BIASNEG: return D3DSPSM_BIASNEG;
482 case BWRITERSPSM_SIGN: return D3DSPSM_SIGN;
483 case BWRITERSPSM_SIGNNEG: return D3DSPSM_SIGNNEG;
484 case BWRITERSPSM_COMP: return D3DSPSM_COMP;
485 case BWRITERSPSM_X2: return D3DSPSM_X2;
486 case BWRITERSPSM_X2NEG: return D3DSPSM_X2NEG;
487 case BWRITERSPSM_DZ: return D3DSPSM_DZ;
488 case BWRITERSPSM_DW: return D3DSPSM_DW;
489 case BWRITERSPSM_ABS: return D3DSPSM_ABS;
490 case BWRITERSPSM_ABSNEG: return D3DSPSM_ABSNEG;
491 case BWRITERSPSM_NOT: return D3DSPSM_NOT;
492 default:
493 FIXME("Unhandled BWRITERSPSM token %#x.\n", bwriter_srcmod);
494 return 0;
498 static uint32_t d3d9_dstmod(uint32_t bwriter_mod)
500 uint32_t ret = 0;
502 if (bwriter_mod & BWRITERSPDM_SATURATE) ret |= D3DSPDM_SATURATE;
503 if (bwriter_mod & BWRITERSPDM_PARTIALPRECISION) ret |= D3DSPDM_PARTIALPRECISION;
504 if (bwriter_mod & BWRITERSPDM_MSAMPCENTROID) ret |= D3DSPDM_MSAMPCENTROID;
506 return ret;
509 static uint32_t d3d9_comparetype(uint32_t asmshader_comparetype)
511 switch (asmshader_comparetype)
513 case BWRITER_COMPARISON_GT: return D3DSPC_GT;
514 case BWRITER_COMPARISON_EQ: return D3DSPC_EQ;
515 case BWRITER_COMPARISON_GE: return D3DSPC_GE;
516 case BWRITER_COMPARISON_LT: return D3DSPC_LT;
517 case BWRITER_COMPARISON_NE: return D3DSPC_NE;
518 case BWRITER_COMPARISON_LE: return D3DSPC_LE;
519 default:
520 FIXME("Unexpected BWRITER_COMPARISON type %#x.\n", asmshader_comparetype);
521 return 0;
525 static uint32_t d3d9_sampler(uint32_t bwriter_sampler)
527 if (bwriter_sampler == BWRITERSTT_UNKNOWN) return D3DSTT_UNKNOWN;
528 if (bwriter_sampler == BWRITERSTT_1D) return D3DSTT_1D;
529 if (bwriter_sampler == BWRITERSTT_2D) return D3DSTT_2D;
530 if (bwriter_sampler == BWRITERSTT_CUBE) return D3DSTT_CUBE;
531 if (bwriter_sampler == BWRITERSTT_VOLUME) return D3DSTT_VOLUME;
532 FIXME("Unexpected BWRITERSAMPLER_TEXTURE_TYPE type %#x.\n", bwriter_sampler);
534 return 0;
537 static uint32_t d3d9_register(uint32_t bwriter_register)
539 if (bwriter_register == BWRITERSPR_TEMP) return D3DSPR_TEMP;
540 if (bwriter_register == BWRITERSPR_INPUT) return D3DSPR_INPUT;
541 if (bwriter_register == BWRITERSPR_CONST) return D3DSPR_CONST;
542 if (bwriter_register == BWRITERSPR_ADDR) return D3DSPR_ADDR;
543 if (bwriter_register == BWRITERSPR_TEXTURE) return D3DSPR_TEXTURE;
544 if (bwriter_register == BWRITERSPR_RASTOUT) return D3DSPR_RASTOUT;
545 if (bwriter_register == BWRITERSPR_ATTROUT) return D3DSPR_ATTROUT;
546 if (bwriter_register == BWRITERSPR_TEXCRDOUT) return D3DSPR_TEXCRDOUT;
547 if (bwriter_register == BWRITERSPR_OUTPUT) return D3DSPR_OUTPUT;
548 if (bwriter_register == BWRITERSPR_CONSTINT) return D3DSPR_CONSTINT;
549 if (bwriter_register == BWRITERSPR_COLOROUT) return D3DSPR_COLOROUT;
550 if (bwriter_register == BWRITERSPR_DEPTHOUT) return D3DSPR_DEPTHOUT;
551 if (bwriter_register == BWRITERSPR_SAMPLER) return D3DSPR_SAMPLER;
552 if (bwriter_register == BWRITERSPR_CONSTBOOL) return D3DSPR_CONSTBOOL;
553 if (bwriter_register == BWRITERSPR_LOOP) return D3DSPR_LOOP;
554 if (bwriter_register == BWRITERSPR_MISCTYPE) return D3DSPR_MISCTYPE;
555 if (bwriter_register == BWRITERSPR_LABEL) return D3DSPR_LABEL;
556 if (bwriter_register == BWRITERSPR_PREDICATE) return D3DSPR_PREDICATE;
558 FIXME("Unexpected BWRITERSPR %#x.\n", bwriter_register);
559 return ~0U;
562 static uint32_t d3d9_opcode(uint32_t bwriter_opcode)
564 switch (bwriter_opcode)
566 case BWRITERSIO_NOP: return D3DSIO_NOP;
567 case BWRITERSIO_MOV: return D3DSIO_MOV;
568 case BWRITERSIO_ADD: return D3DSIO_ADD;
569 case BWRITERSIO_SUB: return D3DSIO_SUB;
570 case BWRITERSIO_MAD: return D3DSIO_MAD;
571 case BWRITERSIO_MUL: return D3DSIO_MUL;
572 case BWRITERSIO_RCP: return D3DSIO_RCP;
573 case BWRITERSIO_RSQ: return D3DSIO_RSQ;
574 case BWRITERSIO_DP3: return D3DSIO_DP3;
575 case BWRITERSIO_DP4: return D3DSIO_DP4;
576 case BWRITERSIO_MIN: return D3DSIO_MIN;
577 case BWRITERSIO_MAX: return D3DSIO_MAX;
578 case BWRITERSIO_SLT: return D3DSIO_SLT;
579 case BWRITERSIO_SGE: return D3DSIO_SGE;
580 case BWRITERSIO_EXP: return D3DSIO_EXP;
581 case BWRITERSIO_LOG: return D3DSIO_LOG;
582 case BWRITERSIO_LIT: return D3DSIO_LIT;
583 case BWRITERSIO_DST: return D3DSIO_DST;
584 case BWRITERSIO_LRP: return D3DSIO_LRP;
585 case BWRITERSIO_FRC: return D3DSIO_FRC;
586 case BWRITERSIO_M4x4: return D3DSIO_M4x4;
587 case BWRITERSIO_M4x3: return D3DSIO_M4x3;
588 case BWRITERSIO_M3x4: return D3DSIO_M3x4;
589 case BWRITERSIO_M3x3: return D3DSIO_M3x3;
590 case BWRITERSIO_M3x2: return D3DSIO_M3x2;
591 case BWRITERSIO_CALL: return D3DSIO_CALL;
592 case BWRITERSIO_CALLNZ: return D3DSIO_CALLNZ;
593 case BWRITERSIO_LOOP: return D3DSIO_LOOP;
594 case BWRITERSIO_RET: return D3DSIO_RET;
595 case BWRITERSIO_ENDLOOP: return D3DSIO_ENDLOOP;
596 case BWRITERSIO_LABEL: return D3DSIO_LABEL;
597 case BWRITERSIO_DCL: return D3DSIO_DCL;
598 case BWRITERSIO_POW: return D3DSIO_POW;
599 case BWRITERSIO_CRS: return D3DSIO_CRS;
600 case BWRITERSIO_SGN: return D3DSIO_SGN;
601 case BWRITERSIO_ABS: return D3DSIO_ABS;
602 case BWRITERSIO_NRM: return D3DSIO_NRM;
603 case BWRITERSIO_SINCOS: return D3DSIO_SINCOS;
604 case BWRITERSIO_REP: return D3DSIO_REP;
605 case BWRITERSIO_ENDREP: return D3DSIO_ENDREP;
606 case BWRITERSIO_IF: return D3DSIO_IF;
607 case BWRITERSIO_IFC: return D3DSIO_IFC;
608 case BWRITERSIO_ELSE: return D3DSIO_ELSE;
609 case BWRITERSIO_ENDIF: return D3DSIO_ENDIF;
610 case BWRITERSIO_BREAK: return D3DSIO_BREAK;
611 case BWRITERSIO_BREAKC: return D3DSIO_BREAKC;
612 case BWRITERSIO_MOVA: return D3DSIO_MOVA;
613 case BWRITERSIO_DEFB: return D3DSIO_DEFB;
614 case BWRITERSIO_DEFI: return D3DSIO_DEFI;
616 case BWRITERSIO_TEXCOORD: return D3DSIO_TEXCOORD;
617 case BWRITERSIO_TEXKILL: return D3DSIO_TEXKILL;
618 case BWRITERSIO_TEX: return D3DSIO_TEX;
619 case BWRITERSIO_TEXBEM: return D3DSIO_TEXBEM;
620 case BWRITERSIO_TEXBEML: return D3DSIO_TEXBEML;
621 case BWRITERSIO_TEXREG2AR: return D3DSIO_TEXREG2AR;
622 case BWRITERSIO_TEXREG2GB: return D3DSIO_TEXREG2GB;
623 case BWRITERSIO_TEXM3x2PAD: return D3DSIO_TEXM3x2PAD;
624 case BWRITERSIO_TEXM3x2TEX: return D3DSIO_TEXM3x2TEX;
625 case BWRITERSIO_TEXM3x3PAD: return D3DSIO_TEXM3x3PAD;
626 case BWRITERSIO_TEXM3x3TEX: return D3DSIO_TEXM3x3TEX;
627 case BWRITERSIO_TEXM3x3SPEC: return D3DSIO_TEXM3x3SPEC;
628 case BWRITERSIO_TEXM3x3VSPEC:return D3DSIO_TEXM3x3VSPEC;
629 case BWRITERSIO_EXPP: return D3DSIO_EXPP;
630 case BWRITERSIO_LOGP: return D3DSIO_LOGP;
631 case BWRITERSIO_CND: return D3DSIO_CND;
632 case BWRITERSIO_DEF: return D3DSIO_DEF;
633 case BWRITERSIO_TEXREG2RGB: return D3DSIO_TEXREG2RGB;
634 case BWRITERSIO_TEXDP3TEX: return D3DSIO_TEXDP3TEX;
635 case BWRITERSIO_TEXM3x2DEPTH:return D3DSIO_TEXM3x2DEPTH;
636 case BWRITERSIO_TEXDP3: return D3DSIO_TEXDP3;
637 case BWRITERSIO_TEXM3x3: return D3DSIO_TEXM3x3;
638 case BWRITERSIO_TEXDEPTH: return D3DSIO_TEXDEPTH;
639 case BWRITERSIO_CMP: return D3DSIO_CMP;
640 case BWRITERSIO_BEM: return D3DSIO_BEM;
641 case BWRITERSIO_DP2ADD: return D3DSIO_DP2ADD;
642 case BWRITERSIO_DSX: return D3DSIO_DSX;
643 case BWRITERSIO_DSY: return D3DSIO_DSY;
644 case BWRITERSIO_TEXLDD: return D3DSIO_TEXLDD;
645 case BWRITERSIO_SETP: return D3DSIO_SETP;
646 case BWRITERSIO_TEXLDL: return D3DSIO_TEXLDL;
647 case BWRITERSIO_BREAKP: return D3DSIO_BREAKP;
649 case BWRITERSIO_PHASE: return D3DSIO_PHASE;
650 case BWRITERSIO_COMMENT: return D3DSIO_COMMENT;
651 case BWRITERSIO_END: return D3DSIO_END;
653 case BWRITERSIO_TEXLDP: return D3DSIO_TEX | D3DSI_TEXLD_PROJECT;
654 case BWRITERSIO_TEXLDB: return D3DSIO_TEX | D3DSI_TEXLD_BIAS;
656 default:
657 FIXME("Unhandled BWRITERSIO token %#x.\n", bwriter_opcode);
658 return ~0U;
662 static uint32_t d3dsp_register(D3DSHADER_PARAM_REGISTER_TYPE type, uint32_t num)
664 return ((type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
665 ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
666 (num & D3DSP_REGNUM_MASK); /* No shift */
669 /******************************************************
670 * Implementation of the writer functions starts here *
671 ******************************************************/
672 static void write_declarations(struct bc_writer *writer, struct bytecode_buffer *buffer,
673 const struct declaration *decls, unsigned int num, uint32_t type)
675 uint32_t instr_dcl = D3DSIO_DCL;
676 uint32_t token;
677 unsigned int i;
678 struct shader_reg reg;
680 ZeroMemory(&reg, sizeof(reg));
682 if (writer->shader->major_version > 1)
683 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
685 for(i = 0; i < num; i++) {
686 if(decls[i].builtin) continue;
688 /* Write the DCL instruction */
689 put_u32(buffer, instr_dcl);
691 /* Write the usage and index */
692 token = (1u << 31); /* Bit 31 of non-instruction opcodes is 1 */
693 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
694 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
695 put_u32(buffer, token);
697 /* Write the dest register */
698 reg.type = type;
699 reg.regnum = decls[i].regnum;
700 reg.writemask = decls[i].writemask;
701 writer->funcs->dstreg(writer, &reg, buffer, 0, decls[i].mod);
705 static void write_const(struct constant **consts, int num, uint32_t opcode, uint32_t reg_type, struct bytecode_buffer *buffer, BOOL len)
707 const uint32_t reg = (1u << 31) | d3dsp_register( reg_type, 0 ) | D3DSP_WRITEMASK_ALL;
708 uint32_t instr_def = opcode;
709 unsigned int i;
711 if(len) {
712 if(opcode == D3DSIO_DEFB)
713 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
714 else
715 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
718 for(i = 0; i < num; i++) {
719 /* Write the DEF instruction */
720 put_u32(buffer, instr_def);
722 put_u32(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
723 put_u32(buffer, consts[i]->value[0].d);
724 if(opcode != D3DSIO_DEFB) {
725 put_u32(buffer, consts[i]->value[1].d);
726 put_u32(buffer, consts[i]->value[2].d);
727 put_u32(buffer, consts[i]->value[3].d);
732 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
733 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
736 /* This function looks for VS 1/2 registers mapping to VS 3 output registers */
737 static HRESULT vs_find_builtin_varyings(struct bc_writer *writer, const struct bwriter_shader *shader)
739 uint32_t usage, usage_idx, writemask, regnum;
740 unsigned int i;
742 for (i = 0; i < shader->num_outputs; i++)
744 if (!shader->outputs[i].builtin)
745 continue;
747 usage = shader->outputs[i].usage;
748 usage_idx = shader->outputs[i].usage_idx;
749 writemask = shader->outputs[i].writemask;
750 regnum = shader->outputs[i].regnum;
752 switch (usage)
754 case BWRITERDECLUSAGE_POSITION:
755 case BWRITERDECLUSAGE_POSITIONT:
756 if (usage_idx > 0)
758 WARN("dcl_position%u not supported in sm 1/2 shaders.\n", usage_idx);
759 return E_INVALIDARG;
761 TRACE("o%u is oPos.\n", regnum);
762 writer->oPos_regnum = regnum;
763 break;
765 case BWRITERDECLUSAGE_COLOR:
766 if (usage_idx > 1)
768 WARN("dcl_color%u not supported in sm 1/2 shaders.\n", usage_idx);
769 return E_INVALIDARG;
771 if (writemask != BWRITERSP_WRITEMASK_ALL)
773 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
774 return E_INVALIDARG;
776 TRACE("o%u is oD%u.\n", regnum, usage_idx);
777 writer->oD_regnum[usage_idx] = regnum;
778 break;
780 case BWRITERDECLUSAGE_TEXCOORD:
781 if (usage_idx >= 8)
783 WARN("dcl_color%u not supported in sm 1/2 shaders.\n", usage_idx);
784 return E_INVALIDARG;
786 if (writemask != (BWRITERSP_WRITEMASK_0)
787 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1)
788 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2)
789 && writemask != (BWRITERSP_WRITEMASK_ALL))
791 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
792 return E_INVALIDARG;
794 TRACE("o%u is oT%u.\n", regnum, usage_idx);
795 writer->oT_regnum[usage_idx] = regnum;
796 break;
798 case BWRITERDECLUSAGE_PSIZE:
799 if (usage_idx > 0)
801 WARN("dcl_psize%u not supported in sm 1/2 shaders.\n", usage_idx);
802 return E_INVALIDARG;
804 TRACE("o%u writemask 0x%08x is oPts.\n", regnum, writemask);
805 writer->oPts_regnum = regnum;
806 writer->oPts_mask = writemask;
807 break;
809 case BWRITERDECLUSAGE_FOG:
810 if (usage_idx > 0)
812 WARN("dcl_fog%u not supported in sm 1 shaders.\n", usage_idx);
813 return E_INVALIDARG;
815 if (writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1
816 && writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3)
818 WARN("Unsupported fog writemask\n");
819 return E_INVALIDARG;
821 TRACE("o%u writemask 0x%08x is oFog.\n", regnum, writemask);
822 writer->oFog_regnum = regnum;
823 writer->oFog_mask = writemask;
824 break;
826 default:
827 WARN("Varying type %u is not supported in shader model 1.x.\n", usage);
828 return E_INVALIDARG;
832 return S_OK;
835 static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
836 HRESULT hr;
838 if(shader->num_ci || shader->num_cb) {
839 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
840 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
841 This->state = E_INVALIDARG;
842 return;
845 hr = vs_find_builtin_varyings(This, shader);
846 if(FAILED(hr)) {
847 This->state = hr;
848 return;
851 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
852 write_constF(shader, buffer, FALSE);
855 static HRESULT find_ps_builtin_semantics(struct bc_writer *writer, const struct bwriter_shader *shader,
856 uint32_t texcoords)
858 uint32_t usage, usage_idx, writemask, regnum;
859 unsigned int i;
861 writer->v_regnum[0] = -1;
862 writer->v_regnum[1] = -1;
863 for (i = 0; i < 8; i++)
864 writer->t_regnum[i] = -1;
866 for (i = 0; i < shader->num_inputs; i++)
868 if (!shader->inputs[i].builtin)
869 continue;
871 usage = shader->inputs[i].usage;
872 usage_idx = shader->inputs[i].usage_idx;
873 writemask = shader->inputs[i].writemask;
874 regnum = shader->inputs[i].regnum;
876 switch (usage)
878 case BWRITERDECLUSAGE_COLOR:
879 if (usage_idx > 1)
881 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
882 return E_INVALIDARG;
884 if (writemask != BWRITERSP_WRITEMASK_ALL)
886 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
887 return E_INVALIDARG;
889 TRACE("v%u is v%u\n", regnum, usage_idx);
890 writer->v_regnum[usage_idx] = regnum;
891 break;
893 case BWRITERDECLUSAGE_TEXCOORD:
894 if (usage_idx > texcoords)
896 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
897 return E_INVALIDARG;
899 if (writemask != (BWRITERSP_WRITEMASK_0)
900 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1)
901 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2)
902 && writemask != (BWRITERSP_WRITEMASK_ALL))
903 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
904 else
905 writemask = BWRITERSP_WRITEMASK_ALL;
906 TRACE("v%u is t%u\n", regnum, usage_idx);
907 writer->t_regnum[usage_idx] = regnum;
908 break;
910 default:
911 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
912 return E_INVALIDARG;
916 return S_OK;
919 static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
920 HRESULT hr;
922 /* First check the constants and varyings, and complain if unsupported things are used */
923 if(shader->num_ci || shader->num_cb) {
924 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
925 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
926 This->state = E_INVALIDARG;
927 return;
930 hr = find_ps_builtin_semantics(This, shader, 4);
931 if(FAILED(hr)) {
932 This->state = hr;
933 return;
936 write_constF(shader, buffer, FALSE);
939 static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
940 HRESULT hr;
942 /* First check the constants and varyings, and complain if unsupported things are used */
943 if(shader->num_ci || shader->num_cb) {
944 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
945 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
946 This->state = E_INVALIDARG;
947 return;
949 hr = find_ps_builtin_semantics(This, shader, 6);
950 if(FAILED(hr)) {
951 This->state = hr;
952 return;
955 write_constF(shader, buffer, FALSE);
958 static void end(struct bc_writer *writer, const struct bwriter_shader *shader, struct bytecode_buffer *buffer)
960 put_u32(buffer, D3DSIO_END);
963 static uint32_t map_vs_output(struct bc_writer *writer, uint32_t regnum, uint32_t mask, BOOL *has_components)
965 unsigned int i;
967 *has_components = TRUE;
968 if (regnum == writer->oPos_regnum)
970 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POSITION );
972 if (regnum == writer->oFog_regnum && mask == writer->oFog_mask)
974 *has_components = FALSE;
975 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_FOG ) | D3DSP_WRITEMASK_ALL;
977 if (regnum == writer->oPts_regnum && mask == writer->oPts_mask)
979 *has_components = FALSE;
980 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POINT_SIZE ) | D3DSP_WRITEMASK_ALL;
982 for (i = 0; i < 2; i++)
984 if (regnum == writer->oD_regnum[i])
985 return d3dsp_register( D3DSPR_ATTROUT, i );
987 for (i = 0; i < 8; i++)
989 if (regnum == writer->oT_regnum[i])
990 return d3dsp_register( D3DSPR_TEXCRDOUT, i );
993 /* The varying must be undeclared - if an unsupported varying was declared,
994 * the vs_find_builtin_varyings function would have caught it and this code
995 * would not run */
996 WARN("Undeclared varying %u.\n", regnum);
997 writer->state = E_INVALIDARG;
998 return -1;
1001 static void vs_12_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1002 uint32_t shift, uint32_t mod)
1004 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1005 BOOL has_wmask;
1007 if (reg->rel_reg)
1009 WARN("Relative addressing not supported for destination registers\n");
1010 writer->state = E_INVALIDARG;
1011 return;
1014 switch (reg->type)
1016 case BWRITERSPR_OUTPUT:
1017 token |= map_vs_output(writer, reg->regnum, reg->writemask, &has_wmask);
1018 break;
1020 case BWRITERSPR_RASTOUT:
1021 case BWRITERSPR_ATTROUT:
1022 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1023 * but are unexpected. If we hit this path it might be due to an error.
1025 FIXME("Unexpected register type %u.\n", reg->type);
1026 /* drop through */
1027 case BWRITERSPR_INPUT:
1028 case BWRITERSPR_TEMP:
1029 case BWRITERSPR_CONST:
1030 token |= d3dsp_register( reg->type, reg->regnum );
1031 has_wmask = TRUE;
1032 break;
1034 case BWRITERSPR_ADDR:
1035 if (reg->regnum != 0)
1037 WARN("Only a0 exists\n");
1038 writer->state = E_INVALIDARG;
1039 return;
1041 token |= d3dsp_register( D3DSPR_ADDR, 0 );
1042 has_wmask = TRUE;
1043 break;
1045 case BWRITERSPR_PREDICATE:
1046 if (writer->shader->major_version != 2 || writer->shader->minor_version != 1)
1048 WARN("Predicate register is allowed only in vs_2_x\n");
1049 writer->state = E_INVALIDARG;
1050 return;
1052 if (reg->regnum != 0)
1054 WARN("Only predicate register p0 exists\n");
1055 writer->state = E_INVALIDARG;
1056 return;
1058 token |= d3dsp_register( D3DSPR_PREDICATE, 0 );
1059 has_wmask = TRUE;
1060 break;
1062 default:
1063 WARN("Invalid register type for 1.x-2.x vertex shader\n");
1064 writer->state = E_INVALIDARG;
1065 return;
1068 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
1069 * into the bytecode and since the compiler doesn't do such checks write them
1070 * (the checks are done by the undocumented shader validator)
1072 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1073 token |= d3d9_dstmod(mod);
1075 if (has_wmask)
1076 token |= d3d9_writemask(reg->writemask);
1077 put_u32(buffer, token);
1080 static void vs_1_x_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1082 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1083 uint32_t component;
1084 BOOL has_swizzle;
1086 switch (reg->type)
1088 case BWRITERSPR_OUTPUT:
1089 /* Map the swizzle to a writemask, the format expected by
1090 * map_vs_output */
1091 switch (reg->swizzle)
1093 case BWRITERVS_SWIZZLE_X:
1094 component = BWRITERSP_WRITEMASK_0;
1095 break;
1096 case BWRITERVS_SWIZZLE_Y:
1097 component = BWRITERSP_WRITEMASK_1;
1098 break;
1099 case BWRITERVS_SWIZZLE_Z:
1100 component = BWRITERSP_WRITEMASK_2;
1101 break;
1102 case BWRITERVS_SWIZZLE_W:
1103 component = BWRITERSP_WRITEMASK_3;
1104 break;
1105 default:
1106 component = 0;
1108 token |= map_vs_output(writer, reg->regnum, component, &has_swizzle);
1109 break;
1111 case BWRITERSPR_RASTOUT:
1112 case BWRITERSPR_ATTROUT:
1113 /* These registers are mapped to input and output regs. They can
1114 * be encoded in the bytecode, but are unexpected. If we hit this
1115 * path it might be due to an error. */
1116 FIXME("Unexpected register type %u.\n", reg->type);
1117 /* drop through */
1118 case BWRITERSPR_INPUT:
1119 case BWRITERSPR_TEMP:
1120 case BWRITERSPR_CONST:
1121 case BWRITERSPR_ADDR:
1122 token |= d3dsp_register(reg->type, reg->regnum);
1123 if (reg->rel_reg)
1125 if (reg->rel_reg->type != BWRITERSPR_ADDR || reg->rel_reg->regnum != 0
1126 || reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X)
1128 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
1129 writer->state = E_INVALIDARG;
1130 return;
1132 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1134 break;
1136 default:
1137 WARN("Invalid register type for 1.x vshader\n");
1138 writer->state = E_INVALIDARG;
1139 return;
1142 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1144 token |= d3d9_srcmod(reg->srcmod);
1145 put_u32(buffer, token);
1148 static void write_srcregs(struct bc_writer *writer, const struct instruction *instr, struct bytecode_buffer *buffer)
1150 unsigned int i;
1152 if (instr->has_predicate)
1153 writer->funcs->srcreg(writer, &instr->predicate, buffer);
1155 for (i = 0; i < instr->num_srcs; ++i)
1156 writer->funcs->srcreg(writer, &instr->src[i], buffer);
1159 static uint32_t map_ps13_temp(struct bc_writer *writer, const struct shader_reg *reg)
1161 if (reg->regnum == T0_REG)
1162 return d3dsp_register(D3DSPR_TEXTURE, 0);
1163 if (reg->regnum == T1_REG)
1164 return d3dsp_register(D3DSPR_TEXTURE, 1);
1165 if(reg->regnum == T2_REG)
1166 return d3dsp_register(D3DSPR_TEXTURE, 2);
1167 if (reg->regnum == T3_REG)
1168 return d3dsp_register(D3DSPR_TEXTURE, 3);
1169 return d3dsp_register(D3DSPR_TEMP, reg->regnum);
1172 static uint32_t map_ps_input(struct bc_writer *writer, const struct shader_reg *reg)
1174 unsigned int i;
1176 /* Map color interpolators */
1177 for (i = 0; i < ARRAY_SIZE(writer->v_regnum); ++i)
1179 if (reg->regnum == writer->v_regnum[i])
1180 return d3dsp_register(D3DSPR_INPUT, i);
1182 for (i = 0; i < ARRAY_SIZE(writer->t_regnum); ++i)
1184 if(reg->regnum == writer->t_regnum[i])
1185 return d3dsp_register(D3DSPR_TEXTURE, i);
1188 WARN("Invalid ps 1/2 varying\n");
1189 writer->state = E_INVALIDARG;
1190 return 0;
1193 static void ps_1_0123_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1195 uint32_t token = 1u << 31;
1197 if (reg->rel_reg)
1199 WARN("Relative addressing not supported in <= ps_3_0\n");
1200 writer->state = E_INVALIDARG;
1201 return;
1204 switch (reg->type)
1206 case BWRITERSPR_INPUT:
1207 token |= map_ps_input(writer, reg);
1208 break;
1210 /* Take care about the texture temporaries. There's a problem: They aren't
1211 * declared anywhere, so we can only hardcode the values that are used
1212 * to map ps_1_3 shaders to the common shader structure
1214 case BWRITERSPR_TEMP:
1215 token |= map_ps13_temp(writer, reg);
1216 break;
1218 case BWRITERSPR_CONST: /* Can be mapped 1:1 */
1219 token |= d3dsp_register( reg->type, reg->regnum );
1220 break;
1222 default:
1223 WARN("Invalid register type for <= ps_1_3 shader\n");
1224 writer->state = E_INVALIDARG;
1225 return;
1228 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1230 if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW
1231 || reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG
1232 || reg->srcmod == BWRITERSPSM_NOT)
1234 WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
1235 writer->state = E_INVALIDARG;
1236 return;
1238 token |= d3d9_srcmod(reg->srcmod);
1239 put_u32(buffer, token);
1242 static void ps_1_0123_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1243 uint32_t shift, uint32_t mod)
1245 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1247 if (reg->rel_reg)
1249 WARN("Relative addressing not supported for destination registers\n");
1250 writer->state = E_INVALIDARG;
1251 return;
1254 switch (reg->type)
1256 case BWRITERSPR_TEMP:
1257 token |= map_ps13_temp(writer, reg);
1258 break;
1260 /* texkill uses the input register as a destination parameter */
1261 case BWRITERSPR_INPUT:
1262 token |= map_ps_input(writer, reg);
1263 break;
1265 default:
1266 WARN("Invalid dest register type for 1.x pshader\n");
1267 writer->state = E_INVALIDARG;
1268 return;
1271 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1272 token |= d3d9_dstmod(mod);
1274 token |= d3d9_writemask(reg->writemask);
1275 put_u32(buffer, token);
1278 /* The length of an instruction consists of the destination register (if any),
1279 * the number of source registers, the number of address registers used for
1280 * indirect addressing, and optionally the predicate register */
1281 static unsigned int instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts)
1283 unsigned int ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
1284 unsigned int i;
1286 if (dsts && instr->dst.rel_reg)
1287 ++ret;
1288 for (i = 0; i < srcs; ++i)
1289 if (instr->src[i].rel_reg)
1290 ++ret;
1291 return ret;
1294 static void sm_1_x_opcode(struct bc_writer *writer, const struct instruction *instr, uint32_t token,
1295 struct bytecode_buffer *buffer)
1297 /* Instruction length isn't encoded in sm_1_x. */
1298 if (instr->coissue)
1299 token |= D3DSI_COISSUE;
1300 put_u32(buffer, token);
1303 static void instr_handler(struct bc_writer *writer, const struct instruction *instr, struct bytecode_buffer *buffer)
1305 uint32_t token = d3d9_opcode(instr->opcode);
1307 writer->funcs->opcode(writer, instr, token, buffer);
1308 if (instr->has_dst)
1309 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1310 write_srcregs(writer, instr, buffer);
1313 static const struct instr_handler_table vs_1_x_handlers[] = {
1314 {BWRITERSIO_ADD, instr_handler},
1315 {BWRITERSIO_NOP, instr_handler},
1316 {BWRITERSIO_MOV, instr_handler},
1317 {BWRITERSIO_SUB, instr_handler},
1318 {BWRITERSIO_MAD, instr_handler},
1319 {BWRITERSIO_MUL, instr_handler},
1320 {BWRITERSIO_RCP, instr_handler},
1321 {BWRITERSIO_RSQ, instr_handler},
1322 {BWRITERSIO_DP3, instr_handler},
1323 {BWRITERSIO_DP4, instr_handler},
1324 {BWRITERSIO_MIN, instr_handler},
1325 {BWRITERSIO_MAX, instr_handler},
1326 {BWRITERSIO_SLT, instr_handler},
1327 {BWRITERSIO_SGE, instr_handler},
1328 {BWRITERSIO_EXP, instr_handler},
1329 {BWRITERSIO_LOG, instr_handler},
1330 {BWRITERSIO_EXPP, instr_handler},
1331 {BWRITERSIO_LOGP, instr_handler},
1332 {BWRITERSIO_DST, instr_handler},
1333 {BWRITERSIO_FRC, instr_handler},
1334 {BWRITERSIO_M4x4, instr_handler},
1335 {BWRITERSIO_M4x3, instr_handler},
1336 {BWRITERSIO_M3x4, instr_handler},
1337 {BWRITERSIO_M3x3, instr_handler},
1338 {BWRITERSIO_M3x2, instr_handler},
1339 {BWRITERSIO_LIT, instr_handler},
1341 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
1342 the end of the list */
1345 static const struct bytecode_backend vs_1_x_backend = {
1346 vs_1_x_header,
1347 end,
1348 vs_1_x_srcreg,
1349 vs_12_dstreg,
1350 sm_1_x_opcode,
1351 vs_1_x_handlers
1354 static void instr_ps_1_0123_texld(struct bc_writer *writer, const struct instruction *instr,
1355 struct bytecode_buffer *buffer)
1357 struct shader_reg reg;
1358 uint32_t swizzlemask;
1359 uint32_t idx;
1361 if (instr->src[1].type != BWRITERSPR_SAMPLER || instr->src[1].regnum > 3)
1363 WARN("Unsupported sampler type %u regnum %u.\n", instr->src[1].type, instr->src[1].regnum);
1364 writer->state = E_INVALIDARG;
1365 return;
1367 else if (instr->dst.type != BWRITERSPR_TEMP)
1369 WARN("Can only sample into a temp register\n");
1370 writer->state = E_INVALIDARG;
1371 return;
1374 idx = instr->src[1].regnum;
1375 if ((idx == 0 && instr->dst.regnum != T0_REG) || (idx == 1 && instr->dst.regnum != T1_REG)
1376 || (idx == 2 && instr->dst.regnum != T2_REG) || (idx == 3 && instr->dst.regnum != T3_REG))
1378 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n", idx, instr->dst.regnum);
1379 writer->state = E_INVALIDARG;
1380 return;
1382 if (instr->src[0].type == BWRITERSPR_INPUT)
1384 /* A simple non-dependent read tex instruction */
1385 if (instr->src[0].regnum != writer->t_regnum[idx])
1387 WARN("Cannot sample from s%u with texture address data from interpolator %u\n", idx, instr->src[0].regnum);
1388 writer->state = E_INVALIDARG;
1389 return;
1391 writer->funcs->opcode(writer, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1393 /* map the temp dstreg to the ps_1_3 texture temporary register */
1394 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1396 else if (instr->src[0].type == BWRITERSPR_TEMP)
1398 swizzlemask = 3 | (3 << 2) | (3 << 4);
1399 if ((instr->src[0].swizzle & swizzlemask) == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z))
1401 TRACE("writing texreg2rgb\n");
1402 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
1404 else if (instr->src[0].swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X))
1406 TRACE("writing texreg2ar\n");
1407 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
1409 else if (instr->src[0].swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z))
1411 TRACE("writing texreg2gb\n");
1412 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
1414 else
1416 WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].swizzle);
1417 writer->state = E_INVALIDARG;
1418 return;
1421 /* Dst and src reg can be mapped normally. Both registers are
1422 * temporary registers in the source shader and have to be mapped to
1423 * the temporary form of the texture registers. However, the src reg
1424 * doesn't have a swizzle. */
1425 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1426 reg = instr->src[0];
1427 reg.swizzle = BWRITERVS_NOSWIZZLE;
1428 writer->funcs->srcreg(writer, &reg, buffer);
1430 else
1432 WARN("Invalid address data source register\n");
1433 writer->state = E_INVALIDARG;
1434 return;
1438 static void instr_ps_1_0123_mov(struct bc_writer *writer, const struct instruction *instr,
1439 struct bytecode_buffer *buffer)
1441 uint32_t token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1443 if (instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT)
1445 if ((instr->dst.regnum == T0_REG && instr->src[0].regnum == writer->t_regnum[0])
1446 || (instr->dst.regnum == T1_REG && instr->src[0].regnum == writer->t_regnum[1])
1447 || (instr->dst.regnum == T2_REG && instr->src[0].regnum == writer->t_regnum[2])
1448 || (instr->dst.regnum == T3_REG && instr->src[0].regnum == writer->t_regnum[3]))
1450 if (instr->dstmod & BWRITERSPDM_SATURATE)
1452 writer->funcs->opcode(writer, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
1453 /* Remove the SATURATE flag, it's implicit to the instruction */
1454 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
1455 return;
1457 else
1459 WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
1460 writer->state = E_INVALIDARG;
1461 return;
1464 else if (instr->src[0].regnum == writer->v_regnum[0] || instr->src[0].regnum == writer->v_regnum[1])
1466 /* Handled by the normal mov below. Just drop out of the if condition */
1468 else
1470 WARN("Unsupported varying -> temp mov in <= ps_1_3\n");
1471 writer->state = E_INVALIDARG;
1472 return;
1476 writer->funcs->opcode(writer, instr, token, buffer);
1477 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1478 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1481 static const struct instr_handler_table ps_1_0123_handlers[] = {
1482 {BWRITERSIO_ADD, instr_handler},
1483 {BWRITERSIO_NOP, instr_handler},
1484 {BWRITERSIO_MOV, instr_ps_1_0123_mov},
1485 {BWRITERSIO_SUB, instr_handler},
1486 {BWRITERSIO_MAD, instr_handler},
1487 {BWRITERSIO_MUL, instr_handler},
1488 {BWRITERSIO_DP3, instr_handler},
1489 {BWRITERSIO_DP4, instr_handler},
1490 {BWRITERSIO_LRP, instr_handler},
1492 /* pshader instructions */
1493 {BWRITERSIO_CND, instr_handler},
1494 {BWRITERSIO_CMP, instr_handler},
1495 {BWRITERSIO_TEXKILL, instr_handler},
1496 {BWRITERSIO_TEX, instr_ps_1_0123_texld},
1497 {BWRITERSIO_TEXBEM, instr_handler},
1498 {BWRITERSIO_TEXBEML, instr_handler},
1499 {BWRITERSIO_TEXM3x2PAD, instr_handler},
1500 {BWRITERSIO_TEXM3x3PAD, instr_handler},
1501 {BWRITERSIO_TEXM3x3SPEC, instr_handler},
1502 {BWRITERSIO_TEXM3x3VSPEC, instr_handler},
1503 {BWRITERSIO_TEXM3x3TEX, instr_handler},
1504 {BWRITERSIO_TEXM3x3, instr_handler},
1505 {BWRITERSIO_TEXM3x2DEPTH, instr_handler},
1506 {BWRITERSIO_TEXM3x2TEX, instr_handler},
1507 {BWRITERSIO_TEXDP3, instr_handler},
1508 {BWRITERSIO_TEXDP3TEX, instr_handler},
1509 {BWRITERSIO_END, NULL},
1512 static const struct bytecode_backend ps_1_0123_backend = {
1513 ps_1_x_header,
1514 end,
1515 ps_1_0123_srcreg,
1516 ps_1_0123_dstreg,
1517 sm_1_x_opcode,
1518 ps_1_0123_handlers
1521 static void ps_1_4_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1523 uint32_t token = 1u << 31; /* Bit 31 of registers is 1. */
1525 if (reg->rel_reg)
1527 WARN("Relative addressing not supported in <= ps_3_0.\n");
1528 writer->state = E_INVALIDARG;
1529 return;
1532 switch (reg->type)
1534 case BWRITERSPR_INPUT:
1535 token |= map_ps_input(writer, reg);
1536 break;
1538 /* Can be mapped 1:1 */
1539 case BWRITERSPR_TEMP:
1540 case BWRITERSPR_CONST:
1541 token |= d3dsp_register( reg->type, reg->regnum );
1542 break;
1544 default:
1545 WARN("Invalid register type for ps_1_4 shader\n");
1546 writer->state = E_INVALIDARG;
1547 return;
1550 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1552 if (reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG || reg->srcmod == BWRITERSPSM_NOT)
1554 WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
1555 writer->state = E_INVALIDARG;
1556 return;
1558 token |= d3d9_srcmod(reg->srcmod);
1559 put_u32(buffer, token);
1562 static void ps_1_4_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1563 uint32_t shift, uint32_t mod)
1565 uint32_t token = 1u << 31; /* Bit 31 of registers is 1. */
1567 if (reg->rel_reg)
1569 WARN("Relative addressing not supported for destination registers\n");
1570 writer->state = E_INVALIDARG;
1571 return;
1574 switch (reg->type)
1576 case BWRITERSPR_TEMP: /* 1:1 mapping */
1577 token |= d3dsp_register( reg->type, reg->regnum );
1578 break;
1580 /* For texkill */
1581 case BWRITERSPR_INPUT:
1582 token |= map_ps_input(writer, reg);
1583 break;
1585 default:
1586 WARN("Invalid dest register type for 1.x pshader\n");
1587 writer->state = E_INVALIDARG;
1588 return;
1591 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1592 token |= d3d9_dstmod(mod);
1594 token |= d3d9_writemask(reg->writemask);
1595 put_u32(buffer, token);
1598 static void instr_ps_1_4_mov(struct bc_writer *writer, const struct instruction *instr,
1599 struct bytecode_buffer *buffer)
1601 uint32_t token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1603 if (instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT)
1605 if (instr->src[0].regnum == writer->t_regnum[0] || instr->src[0].regnum == writer->t_regnum[1]
1606 || instr->src[0].regnum == writer->t_regnum[2] || instr->src[0].regnum == writer->t_regnum[3]
1607 || instr->src[0].regnum == writer->t_regnum[4] || instr->src[0].regnum == writer->t_regnum[5])
1609 /* Similar to a regular mov, but a different opcode */
1610 token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
1612 else if (instr->src[0].regnum == writer->v_regnum[0] || instr->src[0].regnum == writer->v_regnum[1])
1614 /* Handled by the normal mov below. Just drop out of the if condition */
1616 else
1618 WARN("Unsupported varying -> temp mov in ps_1_4\n");
1619 writer->state = E_INVALIDARG;
1620 return;
1624 writer->funcs->opcode(writer, instr, token, buffer);
1625 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1626 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1629 static void instr_ps_1_4_texld(struct bc_writer *writer, const struct instruction *instr,
1630 struct bytecode_buffer *buffer)
1632 if (instr->src[1].type != BWRITERSPR_SAMPLER || instr->src[1].regnum > 5)
1634 WARN("Unsupported sampler type %u regnum %u.\n",
1635 instr->src[1].type, instr->src[1].regnum);
1636 writer->state = E_INVALIDARG;
1637 return;
1639 else if (instr->dst.type != BWRITERSPR_TEMP)
1641 WARN("Can only sample into a temp register\n");
1642 writer->state = E_INVALIDARG;
1643 return;
1646 if (instr->src[1].regnum != instr->dst.regnum)
1648 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4.\n",
1649 instr->src[1].regnum, instr->dst.regnum);
1650 writer->state = E_INVALIDARG;
1651 return;
1654 writer->funcs->opcode(writer, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1655 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1656 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1659 static const struct instr_handler_table ps_1_4_handlers[] = {
1660 {BWRITERSIO_ADD, instr_handler},
1661 {BWRITERSIO_NOP, instr_handler},
1662 {BWRITERSIO_MOV, instr_ps_1_4_mov},
1663 {BWRITERSIO_SUB, instr_handler},
1664 {BWRITERSIO_MAD, instr_handler},
1665 {BWRITERSIO_MUL, instr_handler},
1666 {BWRITERSIO_DP3, instr_handler},
1667 {BWRITERSIO_DP4, instr_handler},
1668 {BWRITERSIO_LRP, instr_handler},
1670 /* pshader instructions */
1671 {BWRITERSIO_CND, instr_handler},
1672 {BWRITERSIO_CMP, instr_handler},
1673 {BWRITERSIO_TEXKILL, instr_handler},
1674 {BWRITERSIO_TEX, instr_ps_1_4_texld},
1675 {BWRITERSIO_TEXDEPTH, instr_handler},
1676 {BWRITERSIO_BEM, instr_handler},
1678 {BWRITERSIO_PHASE, instr_handler},
1679 {BWRITERSIO_END, NULL},
1682 static const struct bytecode_backend ps_1_4_backend = {
1683 ps_1_4_header,
1684 end,
1685 ps_1_4_srcreg,
1686 ps_1_4_dstreg,
1687 sm_1_x_opcode,
1688 ps_1_4_handlers
1691 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1692 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
1695 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1696 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
1699 static void vs_2_header(struct bc_writer *This,
1700 const struct bwriter_shader *shader,
1701 struct bytecode_buffer *buffer) {
1702 HRESULT hr;
1704 hr = vs_find_builtin_varyings(This, shader);
1705 if(FAILED(hr)) {
1706 This->state = hr;
1707 return;
1710 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1711 write_constF(shader, buffer, TRUE);
1712 write_constB(shader, buffer, TRUE);
1713 write_constI(shader, buffer, TRUE);
1716 static void vs_2_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1718 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
1719 uint32_t component;
1720 uint32_t d3d9reg;
1721 BOOL has_swizzle;
1723 switch (reg->type)
1725 case BWRITERSPR_OUTPUT:
1726 /* Map the swizzle to a writemask, the format expected by
1727 * map_vs_output. */
1728 switch (reg->swizzle)
1730 case BWRITERVS_SWIZZLE_X:
1731 component = BWRITERSP_WRITEMASK_0;
1732 break;
1733 case BWRITERVS_SWIZZLE_Y:
1734 component = BWRITERSP_WRITEMASK_1;
1735 break;
1736 case BWRITERVS_SWIZZLE_Z:
1737 component = BWRITERSP_WRITEMASK_2;
1738 break;
1739 case BWRITERVS_SWIZZLE_W:
1740 component = BWRITERSP_WRITEMASK_3;
1741 break;
1742 default:
1743 component = 0;
1745 token |= map_vs_output(writer, reg->regnum, component, &has_swizzle);
1746 break;
1748 case BWRITERSPR_RASTOUT:
1749 case BWRITERSPR_ATTROUT:
1750 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1751 * but are unexpected. If we hit this path it might be due to an error.
1753 FIXME("Unexpected register type %u.\n", reg->type);
1754 /* drop through */
1755 case BWRITERSPR_INPUT:
1756 case BWRITERSPR_TEMP:
1757 case BWRITERSPR_CONST:
1758 case BWRITERSPR_ADDR:
1759 case BWRITERSPR_CONSTINT:
1760 case BWRITERSPR_CONSTBOOL:
1761 case BWRITERSPR_LABEL:
1762 d3d9reg = d3d9_register(reg->type);
1763 token |= d3dsp_register(d3d9reg, reg->regnum);
1764 break;
1766 case BWRITERSPR_LOOP:
1767 if (reg->regnum != 0)
1769 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
1770 writer->state = E_INVALIDARG;
1771 return;
1773 token |= d3dsp_register(D3DSPR_LOOP, 0);
1774 break;
1776 case BWRITERSPR_PREDICATE:
1777 if (writer->shader->major_version != 2 || writer->shader->minor_version != 1)
1779 WARN("Predicate register is allowed only in vs_2_x\n");
1780 writer->state = E_INVALIDARG;
1781 return;
1783 if (reg->regnum > 0)
1785 WARN("Only predicate register 0 is supported\n");
1786 writer->state = E_INVALIDARG;
1787 return;
1789 token |= d3dsp_register(D3DSPR_PREDICATE, 0);
1790 break;
1792 default:
1793 WARN("Invalid register type for 2.0 vshader\n");
1794 writer->state = E_INVALIDARG;
1795 return;
1798 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1799 token |= d3d9_srcmod(reg->srcmod);
1801 if (reg->rel_reg)
1802 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1804 put_u32(buffer, token);
1806 /* vs_2_0 and newer write the register containing the index explicitly in
1807 * the binary code. */
1808 if (token & D3DVS_ADDRMODE_RELATIVE)
1809 vs_2_srcreg(writer, reg->rel_reg, buffer);
1812 static void sm_2_opcode(struct bc_writer *writer, const struct instruction *instr, uint32_t token,
1813 struct bytecode_buffer *buffer)
1815 unsigned int dst_count = instr->has_dst ? 1 : 0;
1817 /* From SM 2 onwards instruction length is encoded in the opcode field. */
1818 token |= instrlen(instr, instr->num_srcs, dst_count) << D3DSI_INSTLENGTH_SHIFT;
1819 if (instr->comptype)
1820 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1821 if (instr->has_predicate)
1822 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1823 put_u32(buffer,token);
1826 static const struct instr_handler_table vs_2_0_handlers[] = {
1827 {BWRITERSIO_ADD, instr_handler},
1828 {BWRITERSIO_NOP, instr_handler},
1829 {BWRITERSIO_MOV, instr_handler},
1830 {BWRITERSIO_SUB, instr_handler},
1831 {BWRITERSIO_MAD, instr_handler},
1832 {BWRITERSIO_MUL, instr_handler},
1833 {BWRITERSIO_RCP, instr_handler},
1834 {BWRITERSIO_RSQ, instr_handler},
1835 {BWRITERSIO_DP3, instr_handler},
1836 {BWRITERSIO_DP4, instr_handler},
1837 {BWRITERSIO_MIN, instr_handler},
1838 {BWRITERSIO_MAX, instr_handler},
1839 {BWRITERSIO_SLT, instr_handler},
1840 {BWRITERSIO_SGE, instr_handler},
1841 {BWRITERSIO_ABS, instr_handler},
1842 {BWRITERSIO_EXP, instr_handler},
1843 {BWRITERSIO_LOG, instr_handler},
1844 {BWRITERSIO_EXPP, instr_handler},
1845 {BWRITERSIO_LOGP, instr_handler},
1846 {BWRITERSIO_DST, instr_handler},
1847 {BWRITERSIO_LRP, instr_handler},
1848 {BWRITERSIO_FRC, instr_handler},
1849 {BWRITERSIO_CRS, instr_handler},
1850 {BWRITERSIO_SGN, instr_handler},
1851 {BWRITERSIO_NRM, instr_handler},
1852 {BWRITERSIO_SINCOS, instr_handler},
1853 {BWRITERSIO_M4x4, instr_handler},
1854 {BWRITERSIO_M4x3, instr_handler},
1855 {BWRITERSIO_M3x4, instr_handler},
1856 {BWRITERSIO_M3x3, instr_handler},
1857 {BWRITERSIO_M3x2, instr_handler},
1858 {BWRITERSIO_LIT, instr_handler},
1859 {BWRITERSIO_POW, instr_handler},
1860 {BWRITERSIO_MOVA, instr_handler},
1862 {BWRITERSIO_CALL, instr_handler},
1863 {BWRITERSIO_CALLNZ, instr_handler},
1864 {BWRITERSIO_REP, instr_handler},
1865 {BWRITERSIO_ENDREP, instr_handler},
1866 {BWRITERSIO_IF, instr_handler},
1867 {BWRITERSIO_LABEL, instr_handler},
1868 {BWRITERSIO_ELSE, instr_handler},
1869 {BWRITERSIO_ENDIF, instr_handler},
1870 {BWRITERSIO_LOOP, instr_handler},
1871 {BWRITERSIO_RET, instr_handler},
1872 {BWRITERSIO_ENDLOOP, instr_handler},
1874 {BWRITERSIO_END, NULL},
1877 static const struct bytecode_backend vs_2_0_backend = {
1878 vs_2_header,
1879 end,
1880 vs_2_srcreg,
1881 vs_12_dstreg,
1882 sm_2_opcode,
1883 vs_2_0_handlers
1886 static const struct instr_handler_table vs_2_x_handlers[] = {
1887 {BWRITERSIO_ADD, instr_handler},
1888 {BWRITERSIO_NOP, instr_handler},
1889 {BWRITERSIO_MOV, instr_handler},
1890 {BWRITERSIO_SUB, instr_handler},
1891 {BWRITERSIO_MAD, instr_handler},
1892 {BWRITERSIO_MUL, instr_handler},
1893 {BWRITERSIO_RCP, instr_handler},
1894 {BWRITERSIO_RSQ, instr_handler},
1895 {BWRITERSIO_DP3, instr_handler},
1896 {BWRITERSIO_DP4, instr_handler},
1897 {BWRITERSIO_MIN, instr_handler},
1898 {BWRITERSIO_MAX, instr_handler},
1899 {BWRITERSIO_SLT, instr_handler},
1900 {BWRITERSIO_SGE, instr_handler},
1901 {BWRITERSIO_ABS, instr_handler},
1902 {BWRITERSIO_EXP, instr_handler},
1903 {BWRITERSIO_LOG, instr_handler},
1904 {BWRITERSIO_EXPP, instr_handler},
1905 {BWRITERSIO_LOGP, instr_handler},
1906 {BWRITERSIO_DST, instr_handler},
1907 {BWRITERSIO_LRP, instr_handler},
1908 {BWRITERSIO_FRC, instr_handler},
1909 {BWRITERSIO_CRS, instr_handler},
1910 {BWRITERSIO_SGN, instr_handler},
1911 {BWRITERSIO_NRM, instr_handler},
1912 {BWRITERSIO_SINCOS, instr_handler},
1913 {BWRITERSIO_M4x4, instr_handler},
1914 {BWRITERSIO_M4x3, instr_handler},
1915 {BWRITERSIO_M3x4, instr_handler},
1916 {BWRITERSIO_M3x3, instr_handler},
1917 {BWRITERSIO_M3x2, instr_handler},
1918 {BWRITERSIO_LIT, instr_handler},
1919 {BWRITERSIO_POW, instr_handler},
1920 {BWRITERSIO_MOVA, instr_handler},
1922 {BWRITERSIO_CALL, instr_handler},
1923 {BWRITERSIO_CALLNZ, instr_handler},
1924 {BWRITERSIO_REP, instr_handler},
1925 {BWRITERSIO_ENDREP, instr_handler},
1926 {BWRITERSIO_IF, instr_handler},
1927 {BWRITERSIO_LABEL, instr_handler},
1928 {BWRITERSIO_IFC, instr_handler},
1929 {BWRITERSIO_ELSE, instr_handler},
1930 {BWRITERSIO_ENDIF, instr_handler},
1931 {BWRITERSIO_BREAK, instr_handler},
1932 {BWRITERSIO_BREAKC, instr_handler},
1933 {BWRITERSIO_LOOP, instr_handler},
1934 {BWRITERSIO_RET, instr_handler},
1935 {BWRITERSIO_ENDLOOP, instr_handler},
1937 {BWRITERSIO_SETP, instr_handler},
1938 {BWRITERSIO_BREAKP, instr_handler},
1940 {BWRITERSIO_END, NULL},
1943 static const struct bytecode_backend vs_2_x_backend = {
1944 vs_2_header,
1945 end,
1946 vs_2_srcreg,
1947 vs_12_dstreg,
1948 sm_2_opcode,
1949 vs_2_x_handlers
1952 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer)
1954 const uint32_t reg = (1u << 31) | d3dsp_register(D3DSPR_SAMPLER, 0) | D3DSP_WRITEMASK_ALL;
1955 uint32_t instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1956 unsigned int i;
1957 uint32_t token;
1959 for (i = 0; i < shader->num_samplers; ++i)
1961 /* Write the DCL instruction */
1962 put_u32(buffer, instr_dcl);
1963 token = 1u << 31;
1964 /* Already shifted */
1965 token |= d3d9_sampler(shader->samplers[i].type) & D3DSP_TEXTURETYPE_MASK;
1966 put_u32(buffer, token);
1967 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1968 token |= d3d9_dstmod(shader->samplers[i].mod);
1969 put_u32(buffer, token);
1973 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1974 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1975 if(FAILED(hr)) {
1976 This->state = hr;
1977 return;
1980 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1981 write_samplers(shader, buffer);
1982 write_constF(shader, buffer, TRUE);
1983 write_constB(shader, buffer, TRUE);
1984 write_constI(shader, buffer, TRUE);
1987 static void ps_2_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1989 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
1990 uint32_t d3d9reg;
1992 if (reg->rel_reg)
1994 WARN("Relative addressing not supported in <= ps_3_0\n");
1995 writer->state = E_INVALIDARG;
1996 return;
1999 switch (reg->type)
2001 case BWRITERSPR_INPUT:
2002 token |= map_ps_input(writer, reg);
2003 break;
2005 /* Can be mapped 1:1 */
2006 case BWRITERSPR_TEMP:
2007 case BWRITERSPR_CONST:
2008 case BWRITERSPR_COLOROUT:
2009 case BWRITERSPR_CONSTBOOL:
2010 case BWRITERSPR_CONSTINT:
2011 case BWRITERSPR_SAMPLER:
2012 case BWRITERSPR_LABEL:
2013 case BWRITERSPR_DEPTHOUT:
2014 d3d9reg = d3d9_register(reg->type);
2015 token |= d3dsp_register(d3d9reg, reg->regnum);
2016 break;
2018 case BWRITERSPR_PREDICATE:
2019 if (writer->shader->minor_version == 0)
2021 WARN("Predicate register not supported in ps_2_0\n");
2022 writer->state = E_INVALIDARG;
2024 if (reg->regnum)
2026 WARN("Predicate register with regnum %u not supported.\n", reg->regnum);
2027 writer->state = E_INVALIDARG;
2029 token |= d3dsp_register(D3DSPR_PREDICATE, 0);
2030 break;
2032 default:
2033 WARN("Invalid register type for ps_2_0 shader\n");
2034 writer->state = E_INVALIDARG;
2035 return;
2038 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
2040 token |= d3d9_srcmod(reg->srcmod);
2041 put_u32(buffer, token);
2044 static void ps_2_0_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
2045 uint32_t shift, uint32_t mod)
2047 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2048 uint32_t d3d9reg;
2050 if (reg->rel_reg)
2052 WARN("Relative addressing not supported for destination registers\n");
2053 writer->state = E_INVALIDARG;
2054 return;
2057 switch (reg->type)
2059 case BWRITERSPR_TEMP: /* 1:1 mapping */
2060 case BWRITERSPR_COLOROUT:
2061 case BWRITERSPR_DEPTHOUT:
2062 d3d9reg = d3d9_register(reg->type);
2063 token |= d3dsp_register(d3d9reg, reg->regnum);
2064 break;
2066 case BWRITERSPR_PREDICATE:
2067 if (writer->shader->minor_version == 0)
2069 WARN("Predicate register not supported in ps_2_0\n");
2070 writer->state = E_INVALIDARG;
2072 token |= d3dsp_register(D3DSPR_PREDICATE, reg->regnum);
2073 break;
2075 /* texkill uses the input register as a destination parameter */
2076 case BWRITERSPR_INPUT:
2077 token |= map_ps_input(writer, reg);
2078 break;
2080 default:
2081 WARN("Invalid dest register type for 2.x pshader\n");
2082 writer->state = E_INVALIDARG;
2083 return;
2086 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
2087 token |= d3d9_dstmod(mod);
2089 token |= d3d9_writemask(reg->writemask);
2090 put_u32(buffer, token);
2093 static const struct instr_handler_table ps_2_0_handlers[] = {
2094 {BWRITERSIO_ADD, instr_handler},
2095 {BWRITERSIO_NOP, instr_handler},
2096 {BWRITERSIO_MOV, instr_handler},
2097 {BWRITERSIO_SUB, instr_handler},
2098 {BWRITERSIO_MAD, instr_handler},
2099 {BWRITERSIO_MUL, instr_handler},
2100 {BWRITERSIO_RCP, instr_handler},
2101 {BWRITERSIO_RSQ, instr_handler},
2102 {BWRITERSIO_DP3, instr_handler},
2103 {BWRITERSIO_DP4, instr_handler},
2104 {BWRITERSIO_MIN, instr_handler},
2105 {BWRITERSIO_MAX, instr_handler},
2106 {BWRITERSIO_ABS, instr_handler},
2107 {BWRITERSIO_EXP, instr_handler},
2108 {BWRITERSIO_LOG, instr_handler},
2109 {BWRITERSIO_EXPP, instr_handler},
2110 {BWRITERSIO_LOGP, instr_handler},
2111 {BWRITERSIO_LRP, instr_handler},
2112 {BWRITERSIO_FRC, instr_handler},
2113 {BWRITERSIO_CRS, instr_handler},
2114 {BWRITERSIO_NRM, instr_handler},
2115 {BWRITERSIO_SINCOS, instr_handler},
2116 {BWRITERSIO_M4x4, instr_handler},
2117 {BWRITERSIO_M4x3, instr_handler},
2118 {BWRITERSIO_M3x4, instr_handler},
2119 {BWRITERSIO_M3x3, instr_handler},
2120 {BWRITERSIO_M3x2, instr_handler},
2121 {BWRITERSIO_POW, instr_handler},
2122 {BWRITERSIO_DP2ADD, instr_handler},
2123 {BWRITERSIO_CMP, instr_handler},
2125 {BWRITERSIO_TEX, instr_handler},
2126 {BWRITERSIO_TEXLDP, instr_handler},
2127 {BWRITERSIO_TEXLDB, instr_handler},
2128 {BWRITERSIO_TEXKILL, instr_handler},
2130 {BWRITERSIO_END, NULL},
2133 static const struct bytecode_backend ps_2_0_backend = {
2134 ps_2_header,
2135 end,
2136 ps_2_srcreg,
2137 ps_2_0_dstreg,
2138 sm_2_opcode,
2139 ps_2_0_handlers
2142 static const struct instr_handler_table ps_2_x_handlers[] = {
2143 {BWRITERSIO_ADD, instr_handler},
2144 {BWRITERSIO_NOP, instr_handler},
2145 {BWRITERSIO_MOV, instr_handler},
2146 {BWRITERSIO_SUB, instr_handler},
2147 {BWRITERSIO_MAD, instr_handler},
2148 {BWRITERSIO_MUL, instr_handler},
2149 {BWRITERSIO_RCP, instr_handler},
2150 {BWRITERSIO_RSQ, instr_handler},
2151 {BWRITERSIO_DP3, instr_handler},
2152 {BWRITERSIO_DP4, instr_handler},
2153 {BWRITERSIO_MIN, instr_handler},
2154 {BWRITERSIO_MAX, instr_handler},
2155 {BWRITERSIO_ABS, instr_handler},
2156 {BWRITERSIO_EXP, instr_handler},
2157 {BWRITERSIO_LOG, instr_handler},
2158 {BWRITERSIO_EXPP, instr_handler},
2159 {BWRITERSIO_LOGP, instr_handler},
2160 {BWRITERSIO_LRP, instr_handler},
2161 {BWRITERSIO_FRC, instr_handler},
2162 {BWRITERSIO_CRS, instr_handler},
2163 {BWRITERSIO_NRM, instr_handler},
2164 {BWRITERSIO_SINCOS, instr_handler},
2165 {BWRITERSIO_M4x4, instr_handler},
2166 {BWRITERSIO_M4x3, instr_handler},
2167 {BWRITERSIO_M3x4, instr_handler},
2168 {BWRITERSIO_M3x3, instr_handler},
2169 {BWRITERSIO_M3x2, instr_handler},
2170 {BWRITERSIO_POW, instr_handler},
2171 {BWRITERSIO_DP2ADD, instr_handler},
2172 {BWRITERSIO_CMP, instr_handler},
2174 {BWRITERSIO_CALL, instr_handler},
2175 {BWRITERSIO_CALLNZ, instr_handler},
2176 {BWRITERSIO_REP, instr_handler},
2177 {BWRITERSIO_ENDREP, instr_handler},
2178 {BWRITERSIO_IF, instr_handler},
2179 {BWRITERSIO_LABEL, instr_handler},
2180 {BWRITERSIO_IFC, instr_handler},
2181 {BWRITERSIO_ELSE, instr_handler},
2182 {BWRITERSIO_ENDIF, instr_handler},
2183 {BWRITERSIO_BREAK, instr_handler},
2184 {BWRITERSIO_BREAKC, instr_handler},
2185 {BWRITERSIO_RET, instr_handler},
2187 {BWRITERSIO_TEX, instr_handler},
2188 {BWRITERSIO_TEXLDP, instr_handler},
2189 {BWRITERSIO_TEXLDB, instr_handler},
2190 {BWRITERSIO_TEXKILL, instr_handler},
2191 {BWRITERSIO_DSX, instr_handler},
2192 {BWRITERSIO_DSY, instr_handler},
2194 {BWRITERSIO_SETP, instr_handler},
2195 {BWRITERSIO_BREAKP, instr_handler},
2197 {BWRITERSIO_TEXLDD, instr_handler},
2199 {BWRITERSIO_END, NULL},
2202 static const struct bytecode_backend ps_2_x_backend = {
2203 ps_2_header,
2204 end,
2205 ps_2_srcreg,
2206 ps_2_0_dstreg,
2207 sm_2_opcode,
2208 ps_2_x_handlers
2211 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
2212 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
2213 write_declarations(This, buffer, shader->outputs, shader->num_outputs, BWRITERSPR_OUTPUT);
2214 write_constF(shader, buffer, TRUE);
2215 write_constB(shader, buffer, TRUE);
2216 write_constI(shader, buffer, TRUE);
2217 write_samplers(shader, buffer);
2220 static void sm_3_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
2222 const struct bwriter_shader *shader = writer->shader;
2223 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2224 uint32_t d3d9reg;
2226 d3d9reg = d3d9_register(reg->type);
2227 token |= d3dsp_register(d3d9reg, reg->regnum);
2228 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
2229 token |= d3d9_srcmod(reg->srcmod);
2231 if (reg->rel_reg)
2233 if (reg->type == BWRITERSPR_CONST && shader->type == ST_PIXEL)
2235 WARN("c%u[...] is unsupported in ps_3_0.\n", reg->regnum);
2236 writer->state = E_INVALIDARG;
2237 return;
2240 if (((reg->rel_reg->type == BWRITERSPR_ADDR && shader->type == ST_VERTEX)
2241 || reg->rel_reg->type == BWRITERSPR_LOOP) && reg->rel_reg->regnum == 0)
2243 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2245 else
2247 WARN("Unsupported relative addressing register\n");
2248 writer->state = E_INVALIDARG;
2249 return;
2253 put_u32(buffer, token);
2255 /* vs_2_0 and newer write the register containing the index explicitly in
2256 * the binary code. */
2257 if (token & D3DVS_ADDRMODE_RELATIVE)
2258 sm_3_srcreg(writer, reg->rel_reg, buffer);
2261 static void sm_3_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
2262 uint32_t shift, uint32_t mod)
2264 const struct bwriter_shader *shader = writer->shader;
2265 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2266 uint32_t d3d9reg;
2268 if (reg->rel_reg)
2270 if (shader->type == ST_VERTEX && reg->type == BWRITERSPR_OUTPUT)
2272 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2274 else
2276 WARN("Relative addressing not supported for this shader type or register type\n");
2277 writer->state = E_INVALIDARG;
2278 return;
2282 d3d9reg = d3d9_register(reg->type);
2283 token |= d3dsp_register(d3d9reg, reg->regnum);
2284 token |= d3d9_dstmod(mod);
2285 token |= d3d9_writemask(reg->writemask);
2286 put_u32(buffer, token);
2288 /* vs_2_0 and newer write the register containing the index explicitly in
2289 * the binary code. */
2290 if (token & D3DVS_ADDRMODE_RELATIVE)
2291 sm_3_srcreg(writer, reg->rel_reg, buffer);
2294 static const struct instr_handler_table vs_3_handlers[] = {
2295 {BWRITERSIO_ADD, instr_handler},
2296 {BWRITERSIO_NOP, instr_handler},
2297 {BWRITERSIO_MOV, instr_handler},
2298 {BWRITERSIO_SUB, instr_handler},
2299 {BWRITERSIO_MAD, instr_handler},
2300 {BWRITERSIO_MUL, instr_handler},
2301 {BWRITERSIO_RCP, instr_handler},
2302 {BWRITERSIO_RSQ, instr_handler},
2303 {BWRITERSIO_DP3, instr_handler},
2304 {BWRITERSIO_DP4, instr_handler},
2305 {BWRITERSIO_MIN, instr_handler},
2306 {BWRITERSIO_MAX, instr_handler},
2307 {BWRITERSIO_SLT, instr_handler},
2308 {BWRITERSIO_SGE, instr_handler},
2309 {BWRITERSIO_ABS, instr_handler},
2310 {BWRITERSIO_EXP, instr_handler},
2311 {BWRITERSIO_LOG, instr_handler},
2312 {BWRITERSIO_EXPP, instr_handler},
2313 {BWRITERSIO_LOGP, instr_handler},
2314 {BWRITERSIO_DST, instr_handler},
2315 {BWRITERSIO_LRP, instr_handler},
2316 {BWRITERSIO_FRC, instr_handler},
2317 {BWRITERSIO_CRS, instr_handler},
2318 {BWRITERSIO_SGN, instr_handler},
2319 {BWRITERSIO_NRM, instr_handler},
2320 {BWRITERSIO_SINCOS, instr_handler},
2321 {BWRITERSIO_M4x4, instr_handler},
2322 {BWRITERSIO_M4x3, instr_handler},
2323 {BWRITERSIO_M3x4, instr_handler},
2324 {BWRITERSIO_M3x3, instr_handler},
2325 {BWRITERSIO_M3x2, instr_handler},
2326 {BWRITERSIO_LIT, instr_handler},
2327 {BWRITERSIO_POW, instr_handler},
2328 {BWRITERSIO_MOVA, instr_handler},
2330 {BWRITERSIO_CALL, instr_handler},
2331 {BWRITERSIO_CALLNZ, instr_handler},
2332 {BWRITERSIO_REP, instr_handler},
2333 {BWRITERSIO_ENDREP, instr_handler},
2334 {BWRITERSIO_IF, instr_handler},
2335 {BWRITERSIO_LABEL, instr_handler},
2336 {BWRITERSIO_IFC, instr_handler},
2337 {BWRITERSIO_ELSE, instr_handler},
2338 {BWRITERSIO_ENDIF, instr_handler},
2339 {BWRITERSIO_BREAK, instr_handler},
2340 {BWRITERSIO_BREAKC, instr_handler},
2341 {BWRITERSIO_LOOP, instr_handler},
2342 {BWRITERSIO_RET, instr_handler},
2343 {BWRITERSIO_ENDLOOP, instr_handler},
2345 {BWRITERSIO_SETP, instr_handler},
2346 {BWRITERSIO_BREAKP, instr_handler},
2347 {BWRITERSIO_TEXLDL, instr_handler},
2349 {BWRITERSIO_END, NULL},
2352 static const struct bytecode_backend vs_3_backend = {
2353 sm_3_header,
2354 end,
2355 sm_3_srcreg,
2356 sm_3_dstreg,
2357 sm_2_opcode,
2358 vs_3_handlers
2361 static const struct instr_handler_table ps_3_handlers[] = {
2362 {BWRITERSIO_ADD, instr_handler},
2363 {BWRITERSIO_NOP, instr_handler},
2364 {BWRITERSIO_MOV, instr_handler},
2365 {BWRITERSIO_SUB, instr_handler},
2366 {BWRITERSIO_MAD, instr_handler},
2367 {BWRITERSIO_MUL, instr_handler},
2368 {BWRITERSIO_RCP, instr_handler},
2369 {BWRITERSIO_RSQ, instr_handler},
2370 {BWRITERSIO_DP3, instr_handler},
2371 {BWRITERSIO_DP4, instr_handler},
2372 {BWRITERSIO_MIN, instr_handler},
2373 {BWRITERSIO_MAX, instr_handler},
2374 {BWRITERSIO_ABS, instr_handler},
2375 {BWRITERSIO_EXP, instr_handler},
2376 {BWRITERSIO_LOG, instr_handler},
2377 {BWRITERSIO_EXPP, instr_handler},
2378 {BWRITERSIO_LOGP, instr_handler},
2379 {BWRITERSIO_LRP, instr_handler},
2380 {BWRITERSIO_FRC, instr_handler},
2381 {BWRITERSIO_CRS, instr_handler},
2382 {BWRITERSIO_NRM, instr_handler},
2383 {BWRITERSIO_SINCOS, instr_handler},
2384 {BWRITERSIO_M4x4, instr_handler},
2385 {BWRITERSIO_M4x3, instr_handler},
2386 {BWRITERSIO_M3x4, instr_handler},
2387 {BWRITERSIO_M3x3, instr_handler},
2388 {BWRITERSIO_M3x2, instr_handler},
2389 {BWRITERSIO_POW, instr_handler},
2390 {BWRITERSIO_DP2ADD, instr_handler},
2391 {BWRITERSIO_CMP, instr_handler},
2393 {BWRITERSIO_CALL, instr_handler},
2394 {BWRITERSIO_CALLNZ, instr_handler},
2395 {BWRITERSIO_REP, instr_handler},
2396 {BWRITERSIO_ENDREP, instr_handler},
2397 {BWRITERSIO_IF, instr_handler},
2398 {BWRITERSIO_LABEL, instr_handler},
2399 {BWRITERSIO_IFC, instr_handler},
2400 {BWRITERSIO_ELSE, instr_handler},
2401 {BWRITERSIO_ENDIF, instr_handler},
2402 {BWRITERSIO_BREAK, instr_handler},
2403 {BWRITERSIO_BREAKC, instr_handler},
2404 {BWRITERSIO_LOOP, instr_handler},
2405 {BWRITERSIO_RET, instr_handler},
2406 {BWRITERSIO_ENDLOOP, instr_handler},
2408 {BWRITERSIO_SETP, instr_handler},
2409 {BWRITERSIO_BREAKP, instr_handler},
2410 {BWRITERSIO_TEXLDL, instr_handler},
2412 {BWRITERSIO_TEX, instr_handler},
2413 {BWRITERSIO_TEXLDP, instr_handler},
2414 {BWRITERSIO_TEXLDB, instr_handler},
2415 {BWRITERSIO_TEXKILL, instr_handler},
2416 {BWRITERSIO_DSX, instr_handler},
2417 {BWRITERSIO_DSY, instr_handler},
2418 {BWRITERSIO_TEXLDD, instr_handler},
2420 {BWRITERSIO_END, NULL},
2423 static const struct bytecode_backend ps_3_backend = {
2424 sm_3_header,
2425 end,
2426 sm_3_srcreg,
2427 sm_3_dstreg,
2428 sm_2_opcode,
2429 ps_3_handlers
2432 static const struct
2434 enum shader_type type;
2435 unsigned char major, minor;
2436 const struct bytecode_backend *backend;
2438 shader_backends[] =
2440 {ST_VERTEX, 1, 0, &vs_1_x_backend},
2441 {ST_VERTEX, 1, 1, &vs_1_x_backend},
2442 {ST_VERTEX, 2, 0, &vs_2_0_backend},
2443 {ST_VERTEX, 2, 1, &vs_2_x_backend},
2444 {ST_VERTEX, 3, 0, &vs_3_backend},
2446 {ST_PIXEL, 1, 0, &ps_1_0123_backend},
2447 {ST_PIXEL, 1, 1, &ps_1_0123_backend},
2448 {ST_PIXEL, 1, 2, &ps_1_0123_backend},
2449 {ST_PIXEL, 1, 3, &ps_1_0123_backend},
2450 {ST_PIXEL, 1, 4, &ps_1_4_backend},
2451 {ST_PIXEL, 2, 0, &ps_2_0_backend},
2452 {ST_PIXEL, 2, 1, &ps_2_x_backend},
2453 {ST_PIXEL, 3, 0, &ps_3_backend},
2456 static HRESULT call_instr_handler(struct bc_writer *writer, const struct instruction *instr,
2457 struct bytecode_buffer *buffer)
2459 unsigned int i;
2461 for (i = 0; writer->funcs->instructions[i].opcode != BWRITERSIO_END; ++i)
2463 if (instr->opcode == writer->funcs->instructions[i].opcode)
2465 if (!writer->funcs->instructions[i].func)
2467 WARN("Opcode %u not supported by this profile.\n", instr->opcode);
2468 return E_INVALIDARG;
2470 writer->funcs->instructions[i].func(writer, instr, buffer);
2471 return S_OK;
2475 FIXME("Unhandled instruction %u - %s.\n", instr->opcode, debug_print_opcode(instr->opcode));
2476 return E_INVALIDARG;
2479 HRESULT shader_write_bytecode(const struct bwriter_shader *shader, uint32_t **result, uint32_t *size)
2481 struct bc_writer *writer;
2482 struct bytecode_buffer *buffer = NULL;
2483 HRESULT hr;
2484 unsigned int i;
2486 if(!shader){
2487 ERR("NULL shader structure, aborting\n");
2488 return E_FAIL;
2491 if (!(writer = calloc(1, sizeof(*writer))))
2492 return E_OUTOFMEMORY;
2494 for (i = 0; i < ARRAY_SIZE(shader_backends); ++i)
2496 if (shader->type == shader_backends[i].type
2497 && shader->major_version == shader_backends[i].major
2498 && shader->minor_version == shader_backends[i].minor)
2500 writer->funcs = shader_backends[i].backend;
2501 break;
2505 if (!writer->funcs)
2507 FIXME("Unsupported shader type %#x, version %u.%u.\n",
2508 shader->type, shader->major_version, shader->minor_version);
2509 free(writer);
2510 return E_NOTIMPL;
2513 writer->shader = shader;
2514 *result = NULL;
2516 buffer = allocate_buffer();
2517 if(!buffer) {
2518 WARN("Failed to allocate a buffer for the shader bytecode\n");
2519 hr = E_FAIL;
2520 goto error;
2523 /* Write shader type and version */
2524 put_u32(buffer, sm1_version(shader));
2526 writer->funcs->header(writer, shader, buffer);
2527 if(FAILED(writer->state)) {
2528 hr = writer->state;
2529 goto error;
2532 for(i = 0; i < shader->num_instrs; i++) {
2533 hr = call_instr_handler(writer, shader->instr[i], buffer);
2534 if(FAILED(hr)) {
2535 goto error;
2539 if(FAILED(writer->state)) {
2540 hr = writer->state;
2541 goto error;
2544 writer->funcs->end(writer, shader, buffer);
2546 if(FAILED(buffer->state)) {
2547 hr = buffer->state;
2548 goto error;
2551 *size = buffer->size * sizeof(uint32_t);
2552 *result = buffer->data;
2553 buffer->data = NULL;
2554 hr = S_OK;
2556 error:
2557 if(buffer) {
2558 free(buffer->data);
2559 free(buffer);
2561 free(writer);
2562 return hr;
2565 void SlDeleteShader(struct bwriter_shader *shader) {
2566 unsigned int i, j;
2568 TRACE("Deleting shader %p\n", shader);
2570 for(i = 0; i < shader->num_cf; i++) {
2571 free(shader->constF[i]);
2573 free(shader->constF);
2574 for(i = 0; i < shader->num_ci; i++) {
2575 free(shader->constI[i]);
2577 free(shader->constI);
2578 for(i = 0; i < shader->num_cb; i++) {
2579 free(shader->constB[i]);
2581 free(shader->constB);
2583 free(shader->inputs);
2584 free(shader->outputs);
2585 free(shader->samplers);
2587 for(i = 0; i < shader->num_instrs; i++) {
2588 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
2589 free(shader->instr[i]->src[j].rel_reg);
2591 free(shader->instr[i]->src);
2592 free(shader->instr[i]->dst.rel_reg);
2593 free(shader->instr[i]);
2595 free(shader->instr);
2597 free(shader);