winedbg: Don't dereference possibly NULL thread pointer.
[wine/zf.git] / dlls / d3dcompiler_43 / bytecodewriter.c
blobd5e55e2c4ed7d55305fe5375dc7bf3768e002022
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 = d3dcompiler_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 = d3dcompiler_alloc(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 = d3dcompiler_alloc(srcs * sizeof(*ret->src));
82 if(!ret->src) {
83 ERR("Failed to allocate memory for instruction registers\n");
84 d3dcompiler_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, DWORD reg, float x, float y, float z, float w) {
117 struct constant *newconst;
119 if(shader->num_cf) {
120 struct constant **newarray;
121 newarray = d3dcompiler_realloc(shader->constF,
122 sizeof(*shader->constF) * (shader->num_cf + 1));
123 if(!newarray) {
124 ERR("Failed to grow the constants array\n");
125 return FALSE;
127 shader->constF = newarray;
128 } else {
129 shader->constF = d3dcompiler_alloc(sizeof(*shader->constF));
130 if(!shader->constF) {
131 ERR("Failed to allocate the constants array\n");
132 return FALSE;
136 newconst = d3dcompiler_alloc(sizeof(*newconst));
137 if(!newconst) {
138 ERR("Failed to allocate a new constant\n");
139 return FALSE;
141 newconst->regnum = reg;
142 newconst->value[0].f = x;
143 newconst->value[1].f = y;
144 newconst->value[2].f = z;
145 newconst->value[3].f = w;
146 shader->constF[shader->num_cf] = newconst;
148 shader->num_cf++;
149 return TRUE;
152 BOOL add_constI(struct bwriter_shader *shader, DWORD reg, INT x, INT y, INT z, INT w) {
153 struct constant *newconst;
155 if(shader->num_ci) {
156 struct constant **newarray;
157 newarray = d3dcompiler_realloc(shader->constI,
158 sizeof(*shader->constI) * (shader->num_ci + 1));
159 if(!newarray) {
160 ERR("Failed to grow the constants array\n");
161 return FALSE;
163 shader->constI = newarray;
164 } else {
165 shader->constI = d3dcompiler_alloc(sizeof(*shader->constI));
166 if(!shader->constI) {
167 ERR("Failed to allocate the constants array\n");
168 return FALSE;
172 newconst = d3dcompiler_alloc(sizeof(*newconst));
173 if(!newconst) {
174 ERR("Failed to allocate a new constant\n");
175 return FALSE;
177 newconst->regnum = reg;
178 newconst->value[0].i = x;
179 newconst->value[1].i = y;
180 newconst->value[2].i = z;
181 newconst->value[3].i = w;
182 shader->constI[shader->num_ci] = newconst;
184 shader->num_ci++;
185 return TRUE;
188 BOOL add_constB(struct bwriter_shader *shader, DWORD reg, BOOL x) {
189 struct constant *newconst;
191 if(shader->num_cb) {
192 struct constant **newarray;
193 newarray = d3dcompiler_realloc(shader->constB,
194 sizeof(*shader->constB) * (shader->num_cb + 1));
195 if(!newarray) {
196 ERR("Failed to grow the constants array\n");
197 return FALSE;
199 shader->constB = newarray;
200 } else {
201 shader->constB = d3dcompiler_alloc(sizeof(*shader->constB));
202 if(!shader->constB) {
203 ERR("Failed to allocate the constants array\n");
204 return FALSE;
208 newconst = d3dcompiler_alloc(sizeof(*newconst));
209 if(!newconst) {
210 ERR("Failed to allocate a new constant\n");
211 return FALSE;
213 newconst->regnum = reg;
214 newconst->value[0].b = x;
215 shader->constB[shader->num_cb] = newconst;
217 shader->num_cb++;
218 return TRUE;
221 BOOL record_declaration(struct bwriter_shader *shader, DWORD usage,
222 DWORD usage_idx, DWORD mod, BOOL output,
223 DWORD regnum, DWORD writemask, BOOL builtin) {
224 unsigned int *num;
225 struct declaration **decl;
226 unsigned int i;
228 if(!shader) return FALSE;
230 if(output) {
231 num = &shader->num_outputs;
232 decl = &shader->outputs;
233 } else {
234 num = &shader->num_inputs;
235 decl = &shader->inputs;
238 if(*num == 0) {
239 *decl = d3dcompiler_alloc(sizeof(**decl));
240 if(!*decl) {
241 ERR("Error allocating declarations array\n");
242 return FALSE;
244 } else {
245 struct declaration *newdecl;
246 for(i = 0; i < *num; i++) {
247 if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) {
248 WARN("Declaration of register %u already exists, writemask match 0x%x\n",
249 regnum, (*decl)[i].writemask & writemask);
253 newdecl = d3dcompiler_realloc(*decl,
254 sizeof(**decl) * ((*num) + 1));
255 if(!newdecl) {
256 ERR("Error reallocating declarations array\n");
257 return FALSE;
259 *decl = newdecl;
261 (*decl)[*num].usage = usage;
262 (*decl)[*num].usage_idx = usage_idx;
263 (*decl)[*num].regnum = regnum;
264 (*decl)[*num].mod = mod;
265 (*decl)[*num].writemask = writemask;
266 (*decl)[*num].builtin = builtin;
267 (*num)++;
269 return TRUE;
272 BOOL record_sampler(struct bwriter_shader *shader, DWORD samptype, DWORD mod, DWORD regnum) {
273 unsigned int i;
275 if(!shader) return FALSE;
277 if(shader->num_samplers == 0) {
278 shader->samplers = d3dcompiler_alloc(sizeof(*shader->samplers));
279 if(!shader->samplers) {
280 ERR("Error allocating samplers array\n");
281 return FALSE;
283 } else {
284 struct samplerdecl *newarray;
286 for(i = 0; i < shader->num_samplers; i++) {
287 if(shader->samplers[i].regnum == regnum) {
288 WARN("Sampler %u already declared\n", regnum);
289 /* This is not an error as far as the assembler is concerned.
290 * Direct3D might refuse to load the compiled shader though
295 newarray = d3dcompiler_realloc(shader->samplers,
296 sizeof(*shader->samplers) * (shader->num_samplers + 1));
297 if(!newarray) {
298 ERR("Error reallocating samplers array\n");
299 return FALSE;
301 shader->samplers = newarray;
304 shader->samplers[shader->num_samplers].type = samptype;
305 shader->samplers[shader->num_samplers].mod = mod;
306 shader->samplers[shader->num_samplers].regnum = regnum;
307 shader->num_samplers++;
308 return TRUE;
311 struct bytecode_buffer
313 DWORD *data;
314 unsigned int size, alloc_size;
315 HRESULT state;
318 struct bc_writer;
320 typedef void (*instr_writer)(struct bc_writer *writer, const struct instruction *instr,
321 struct bytecode_buffer *buffer);
323 struct bytecode_backend
325 void (*header)(struct bc_writer *writer, const struct bwriter_shader *shader,
326 struct bytecode_buffer *buffer);
327 void (*end)(struct bc_writer *writer, const struct bwriter_shader *shader,
328 struct bytecode_buffer *buffer);
329 void (*srcreg)(struct bc_writer *writer, const struct shader_reg *reg,
330 struct bytecode_buffer *buffer);
331 void (*dstreg)(struct bc_writer *writer, const struct shader_reg *reg,
332 struct bytecode_buffer *buffer, DWORD shift, DWORD mod);
333 void (*opcode)(struct bc_writer *writer, const struct instruction *instr,
334 DWORD token, struct bytecode_buffer *buffer);
336 const struct instr_handler_table
338 DWORD opcode;
339 instr_writer func;
340 } *instructions;
343 struct bc_writer
345 const struct bytecode_backend *funcs;
346 const struct bwriter_shader *shader;
348 HRESULT state;
350 /* Vertex shader varying mapping. */
351 DWORD oPos_regnum, oD_regnum[2], oT_regnum[8], oFog_regnum, oFog_mask, oPts_regnum, oPts_mask;
353 /* Pixel shader varying mapping. */
354 DWORD t_regnum[8], v_regnum[2];
358 /* shader bytecode buffer manipulation functions.
359 * allocate_buffer creates a new buffer structure, put_dword adds a new
360 * DWORD to the buffer. In the rare case of a memory allocation failure
361 * when trying to grow the buffer a flag is set in the buffer to mark it
362 * invalid. This avoids return value checking and passing in many places
364 static struct bytecode_buffer *allocate_buffer(void) {
365 struct bytecode_buffer *ret;
367 ret = d3dcompiler_alloc(sizeof(*ret));
368 if(!ret) return NULL;
369 ret->state = S_OK;
370 return ret;
373 static void put_dword(struct bytecode_buffer *buffer, DWORD value) {
374 if(FAILED(buffer->state)) return;
376 if (!array_reserve((void **)&buffer->data, &buffer->alloc_size, buffer->size + 1, sizeof(*buffer->data)))
378 buffer->state = E_OUTOFMEMORY;
379 return;
382 buffer->data[buffer->size++] = value;
385 /* bwriter -> d3d9 conversion functions. */
387 static DWORD sm1_version(const struct bwriter_shader *shader)
389 switch (shader->type)
391 case ST_VERTEX:
392 return D3DVS_VERSION(shader->major_version, shader->minor_version);
393 case ST_PIXEL:
394 return D3DPS_VERSION(shader->major_version, shader->minor_version);
395 default:
396 ERR("Invalid shader type %#x.\n", shader->type);
397 return 0;
401 static DWORD d3d9_swizzle(DWORD bwriter_swizzle)
403 DWORD ret = 0;
405 if ((bwriter_swizzle & BWRITERVS_X_X) == BWRITERVS_X_X) ret |= D3DVS_X_X;
406 if ((bwriter_swizzle & BWRITERVS_X_Y) == BWRITERVS_X_Y) ret |= D3DVS_X_Y;
407 if ((bwriter_swizzle & BWRITERVS_X_Z) == BWRITERVS_X_Z) ret |= D3DVS_X_Z;
408 if ((bwriter_swizzle & BWRITERVS_X_W) == BWRITERVS_X_W) ret |= D3DVS_X_W;
410 if ((bwriter_swizzle & BWRITERVS_Y_X) == BWRITERVS_Y_X) ret |= D3DVS_Y_X;
411 if ((bwriter_swizzle & BWRITERVS_Y_Y) == BWRITERVS_Y_Y) ret |= D3DVS_Y_Y;
412 if ((bwriter_swizzle & BWRITERVS_Y_Z) == BWRITERVS_Y_Z) ret |= D3DVS_Y_Z;
413 if ((bwriter_swizzle & BWRITERVS_Y_W) == BWRITERVS_Y_W) ret |= D3DVS_Y_W;
415 if ((bwriter_swizzle & BWRITERVS_Z_X) == BWRITERVS_Z_X) ret |= D3DVS_Z_X;
416 if ((bwriter_swizzle & BWRITERVS_Z_Y) == BWRITERVS_Z_Y) ret |= D3DVS_Z_Y;
417 if ((bwriter_swizzle & BWRITERVS_Z_Z) == BWRITERVS_Z_Z) ret |= D3DVS_Z_Z;
418 if ((bwriter_swizzle & BWRITERVS_Z_W) == BWRITERVS_Z_W) ret |= D3DVS_Z_W;
420 if ((bwriter_swizzle & BWRITERVS_W_X) == BWRITERVS_W_X) ret |= D3DVS_W_X;
421 if ((bwriter_swizzle & BWRITERVS_W_Y) == BWRITERVS_W_Y) ret |= D3DVS_W_Y;
422 if ((bwriter_swizzle & BWRITERVS_W_Z) == BWRITERVS_W_Z) ret |= D3DVS_W_Z;
423 if ((bwriter_swizzle & BWRITERVS_W_W) == BWRITERVS_W_W) ret |= D3DVS_W_W;
425 return ret;
428 static DWORD d3d9_writemask(DWORD bwriter_writemask)
430 DWORD ret = 0;
432 if (bwriter_writemask & BWRITERSP_WRITEMASK_0) ret |= D3DSP_WRITEMASK_0;
433 if (bwriter_writemask & BWRITERSP_WRITEMASK_1) ret |= D3DSP_WRITEMASK_1;
434 if (bwriter_writemask & BWRITERSP_WRITEMASK_2) ret |= D3DSP_WRITEMASK_2;
435 if (bwriter_writemask & BWRITERSP_WRITEMASK_3) ret |= D3DSP_WRITEMASK_3;
437 return ret;
440 static DWORD d3d9_srcmod(DWORD bwriter_srcmod)
442 switch (bwriter_srcmod)
444 case BWRITERSPSM_NONE: return D3DSPSM_NONE;
445 case BWRITERSPSM_NEG: return D3DSPSM_NEG;
446 case BWRITERSPSM_BIAS: return D3DSPSM_BIAS;
447 case BWRITERSPSM_BIASNEG: return D3DSPSM_BIASNEG;
448 case BWRITERSPSM_SIGN: return D3DSPSM_SIGN;
449 case BWRITERSPSM_SIGNNEG: return D3DSPSM_SIGNNEG;
450 case BWRITERSPSM_COMP: return D3DSPSM_COMP;
451 case BWRITERSPSM_X2: return D3DSPSM_X2;
452 case BWRITERSPSM_X2NEG: return D3DSPSM_X2NEG;
453 case BWRITERSPSM_DZ: return D3DSPSM_DZ;
454 case BWRITERSPSM_DW: return D3DSPSM_DW;
455 case BWRITERSPSM_ABS: return D3DSPSM_ABS;
456 case BWRITERSPSM_ABSNEG: return D3DSPSM_ABSNEG;
457 case BWRITERSPSM_NOT: return D3DSPSM_NOT;
458 default:
459 FIXME("Unhandled BWRITERSPSM token %#x.\n", bwriter_srcmod);
460 return 0;
464 static DWORD d3d9_dstmod(DWORD bwriter_mod)
466 DWORD ret = 0;
468 if (bwriter_mod & BWRITERSPDM_SATURATE) ret |= D3DSPDM_SATURATE;
469 if (bwriter_mod & BWRITERSPDM_PARTIALPRECISION) ret |= D3DSPDM_PARTIALPRECISION;
470 if (bwriter_mod & BWRITERSPDM_MSAMPCENTROID) ret |= D3DSPDM_MSAMPCENTROID;
472 return ret;
475 static DWORD d3d9_comparetype(DWORD asmshader_comparetype)
477 switch (asmshader_comparetype)
479 case BWRITER_COMPARISON_GT: return D3DSPC_GT;
480 case BWRITER_COMPARISON_EQ: return D3DSPC_EQ;
481 case BWRITER_COMPARISON_GE: return D3DSPC_GE;
482 case BWRITER_COMPARISON_LT: return D3DSPC_LT;
483 case BWRITER_COMPARISON_NE: return D3DSPC_NE;
484 case BWRITER_COMPARISON_LE: return D3DSPC_LE;
485 default:
486 FIXME("Unexpected BWRITER_COMPARISON type %#x.\n", asmshader_comparetype);
487 return 0;
491 static DWORD d3d9_sampler(DWORD bwriter_sampler)
493 if (bwriter_sampler == BWRITERSTT_UNKNOWN) return D3DSTT_UNKNOWN;
494 if (bwriter_sampler == BWRITERSTT_1D) return D3DSTT_1D;
495 if (bwriter_sampler == BWRITERSTT_2D) return D3DSTT_2D;
496 if (bwriter_sampler == BWRITERSTT_CUBE) return D3DSTT_CUBE;
497 if (bwriter_sampler == BWRITERSTT_VOLUME) return D3DSTT_VOLUME;
498 FIXME("Unexpected BWRITERSAMPLER_TEXTURE_TYPE type %#x.\n", bwriter_sampler);
500 return 0;
503 static DWORD d3d9_register(DWORD bwriter_register)
505 if (bwriter_register == BWRITERSPR_TEMP) return D3DSPR_TEMP;
506 if (bwriter_register == BWRITERSPR_INPUT) return D3DSPR_INPUT;
507 if (bwriter_register == BWRITERSPR_CONST) return D3DSPR_CONST;
508 if (bwriter_register == BWRITERSPR_ADDR) return D3DSPR_ADDR;
509 if (bwriter_register == BWRITERSPR_TEXTURE) return D3DSPR_TEXTURE;
510 if (bwriter_register == BWRITERSPR_RASTOUT) return D3DSPR_RASTOUT;
511 if (bwriter_register == BWRITERSPR_ATTROUT) return D3DSPR_ATTROUT;
512 if (bwriter_register == BWRITERSPR_TEXCRDOUT) return D3DSPR_TEXCRDOUT;
513 if (bwriter_register == BWRITERSPR_OUTPUT) return D3DSPR_OUTPUT;
514 if (bwriter_register == BWRITERSPR_CONSTINT) return D3DSPR_CONSTINT;
515 if (bwriter_register == BWRITERSPR_COLOROUT) return D3DSPR_COLOROUT;
516 if (bwriter_register == BWRITERSPR_DEPTHOUT) return D3DSPR_DEPTHOUT;
517 if (bwriter_register == BWRITERSPR_SAMPLER) return D3DSPR_SAMPLER;
518 if (bwriter_register == BWRITERSPR_CONSTBOOL) return D3DSPR_CONSTBOOL;
519 if (bwriter_register == BWRITERSPR_LOOP) return D3DSPR_LOOP;
520 if (bwriter_register == BWRITERSPR_MISCTYPE) return D3DSPR_MISCTYPE;
521 if (bwriter_register == BWRITERSPR_LABEL) return D3DSPR_LABEL;
522 if (bwriter_register == BWRITERSPR_PREDICATE) return D3DSPR_PREDICATE;
524 FIXME("Unexpected BWRITERSPR %#x.\n", bwriter_register);
525 return ~0U;
528 static DWORD d3d9_opcode(DWORD bwriter_opcode)
530 switch (bwriter_opcode)
532 case BWRITERSIO_NOP: return D3DSIO_NOP;
533 case BWRITERSIO_MOV: return D3DSIO_MOV;
534 case BWRITERSIO_ADD: return D3DSIO_ADD;
535 case BWRITERSIO_SUB: return D3DSIO_SUB;
536 case BWRITERSIO_MAD: return D3DSIO_MAD;
537 case BWRITERSIO_MUL: return D3DSIO_MUL;
538 case BWRITERSIO_RCP: return D3DSIO_RCP;
539 case BWRITERSIO_RSQ: return D3DSIO_RSQ;
540 case BWRITERSIO_DP3: return D3DSIO_DP3;
541 case BWRITERSIO_DP4: return D3DSIO_DP4;
542 case BWRITERSIO_MIN: return D3DSIO_MIN;
543 case BWRITERSIO_MAX: return D3DSIO_MAX;
544 case BWRITERSIO_SLT: return D3DSIO_SLT;
545 case BWRITERSIO_SGE: return D3DSIO_SGE;
546 case BWRITERSIO_EXP: return D3DSIO_EXP;
547 case BWRITERSIO_LOG: return D3DSIO_LOG;
548 case BWRITERSIO_LIT: return D3DSIO_LIT;
549 case BWRITERSIO_DST: return D3DSIO_DST;
550 case BWRITERSIO_LRP: return D3DSIO_LRP;
551 case BWRITERSIO_FRC: return D3DSIO_FRC;
552 case BWRITERSIO_M4x4: return D3DSIO_M4x4;
553 case BWRITERSIO_M4x3: return D3DSIO_M4x3;
554 case BWRITERSIO_M3x4: return D3DSIO_M3x4;
555 case BWRITERSIO_M3x3: return D3DSIO_M3x3;
556 case BWRITERSIO_M3x2: return D3DSIO_M3x2;
557 case BWRITERSIO_CALL: return D3DSIO_CALL;
558 case BWRITERSIO_CALLNZ: return D3DSIO_CALLNZ;
559 case BWRITERSIO_LOOP: return D3DSIO_LOOP;
560 case BWRITERSIO_RET: return D3DSIO_RET;
561 case BWRITERSIO_ENDLOOP: return D3DSIO_ENDLOOP;
562 case BWRITERSIO_LABEL: return D3DSIO_LABEL;
563 case BWRITERSIO_DCL: return D3DSIO_DCL;
564 case BWRITERSIO_POW: return D3DSIO_POW;
565 case BWRITERSIO_CRS: return D3DSIO_CRS;
566 case BWRITERSIO_SGN: return D3DSIO_SGN;
567 case BWRITERSIO_ABS: return D3DSIO_ABS;
568 case BWRITERSIO_NRM: return D3DSIO_NRM;
569 case BWRITERSIO_SINCOS: return D3DSIO_SINCOS;
570 case BWRITERSIO_REP: return D3DSIO_REP;
571 case BWRITERSIO_ENDREP: return D3DSIO_ENDREP;
572 case BWRITERSIO_IF: return D3DSIO_IF;
573 case BWRITERSIO_IFC: return D3DSIO_IFC;
574 case BWRITERSIO_ELSE: return D3DSIO_ELSE;
575 case BWRITERSIO_ENDIF: return D3DSIO_ENDIF;
576 case BWRITERSIO_BREAK: return D3DSIO_BREAK;
577 case BWRITERSIO_BREAKC: return D3DSIO_BREAKC;
578 case BWRITERSIO_MOVA: return D3DSIO_MOVA;
579 case BWRITERSIO_DEFB: return D3DSIO_DEFB;
580 case BWRITERSIO_DEFI: return D3DSIO_DEFI;
582 case BWRITERSIO_TEXCOORD: return D3DSIO_TEXCOORD;
583 case BWRITERSIO_TEXKILL: return D3DSIO_TEXKILL;
584 case BWRITERSIO_TEX: return D3DSIO_TEX;
585 case BWRITERSIO_TEXBEM: return D3DSIO_TEXBEM;
586 case BWRITERSIO_TEXBEML: return D3DSIO_TEXBEML;
587 case BWRITERSIO_TEXREG2AR: return D3DSIO_TEXREG2AR;
588 case BWRITERSIO_TEXREG2GB: return D3DSIO_TEXREG2GB;
589 case BWRITERSIO_TEXM3x2PAD: return D3DSIO_TEXM3x2PAD;
590 case BWRITERSIO_TEXM3x2TEX: return D3DSIO_TEXM3x2TEX;
591 case BWRITERSIO_TEXM3x3PAD: return D3DSIO_TEXM3x3PAD;
592 case BWRITERSIO_TEXM3x3TEX: return D3DSIO_TEXM3x3TEX;
593 case BWRITERSIO_TEXM3x3SPEC: return D3DSIO_TEXM3x3SPEC;
594 case BWRITERSIO_TEXM3x3VSPEC:return D3DSIO_TEXM3x3VSPEC;
595 case BWRITERSIO_EXPP: return D3DSIO_EXPP;
596 case BWRITERSIO_LOGP: return D3DSIO_LOGP;
597 case BWRITERSIO_CND: return D3DSIO_CND;
598 case BWRITERSIO_DEF: return D3DSIO_DEF;
599 case BWRITERSIO_TEXREG2RGB: return D3DSIO_TEXREG2RGB;
600 case BWRITERSIO_TEXDP3TEX: return D3DSIO_TEXDP3TEX;
601 case BWRITERSIO_TEXM3x2DEPTH:return D3DSIO_TEXM3x2DEPTH;
602 case BWRITERSIO_TEXDP3: return D3DSIO_TEXDP3;
603 case BWRITERSIO_TEXM3x3: return D3DSIO_TEXM3x3;
604 case BWRITERSIO_TEXDEPTH: return D3DSIO_TEXDEPTH;
605 case BWRITERSIO_CMP: return D3DSIO_CMP;
606 case BWRITERSIO_BEM: return D3DSIO_BEM;
607 case BWRITERSIO_DP2ADD: return D3DSIO_DP2ADD;
608 case BWRITERSIO_DSX: return D3DSIO_DSX;
609 case BWRITERSIO_DSY: return D3DSIO_DSY;
610 case BWRITERSIO_TEXLDD: return D3DSIO_TEXLDD;
611 case BWRITERSIO_SETP: return D3DSIO_SETP;
612 case BWRITERSIO_TEXLDL: return D3DSIO_TEXLDL;
613 case BWRITERSIO_BREAKP: return D3DSIO_BREAKP;
615 case BWRITERSIO_PHASE: return D3DSIO_PHASE;
616 case BWRITERSIO_COMMENT: return D3DSIO_COMMENT;
617 case BWRITERSIO_END: return D3DSIO_END;
619 case BWRITERSIO_TEXLDP: return D3DSIO_TEX | D3DSI_TEXLD_PROJECT;
620 case BWRITERSIO_TEXLDB: return D3DSIO_TEX | D3DSI_TEXLD_BIAS;
622 default:
623 FIXME("Unhandled BWRITERSIO token %#x.\n", bwriter_opcode);
624 return ~0U;
628 static DWORD d3dsp_register( D3DSHADER_PARAM_REGISTER_TYPE type, DWORD num )
630 return ((type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
631 ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
632 (num & D3DSP_REGNUM_MASK); /* No shift */
635 /******************************************************
636 * Implementation of the writer functions starts here *
637 ******************************************************/
638 static void write_declarations(struct bc_writer *This, struct bytecode_buffer *buffer,
639 const struct declaration *decls, unsigned int num, DWORD type)
641 DWORD i;
642 DWORD instr_dcl = D3DSIO_DCL;
643 DWORD token;
644 struct shader_reg reg;
646 ZeroMemory(&reg, sizeof(reg));
648 if (This->shader->major_version > 1)
649 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
651 for(i = 0; i < num; i++) {
652 if(decls[i].builtin) continue;
654 /* Write the DCL instruction */
655 put_dword(buffer, instr_dcl);
657 /* Write the usage and index */
658 token = (1u << 31); /* Bit 31 of non-instruction opcodes is 1 */
659 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
660 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
661 put_dword(buffer, token);
663 /* Write the dest register */
664 reg.type = type;
665 reg.regnum = decls[i].regnum;
666 reg.u.writemask = decls[i].writemask;
667 This->funcs->dstreg(This, &reg, buffer, 0, decls[i].mod);
671 static void write_const(struct constant **consts, int num, DWORD opcode, DWORD reg_type, struct bytecode_buffer *buffer, BOOL len) {
672 int i;
673 DWORD instr_def = opcode;
674 const DWORD reg = (1u << 31) | d3dsp_register( reg_type, 0 ) | D3DSP_WRITEMASK_ALL;
676 if(len) {
677 if(opcode == D3DSIO_DEFB)
678 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
679 else
680 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
683 for(i = 0; i < num; i++) {
684 /* Write the DEF instruction */
685 put_dword(buffer, instr_def);
687 put_dword(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
688 put_dword(buffer, consts[i]->value[0].d);
689 if(opcode != D3DSIO_DEFB) {
690 put_dword(buffer, consts[i]->value[1].d);
691 put_dword(buffer, consts[i]->value[2].d);
692 put_dword(buffer, consts[i]->value[3].d);
697 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
698 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
701 /* This function looks for VS 1/2 registers mapping to VS 3 output registers */
702 static HRESULT vs_find_builtin_varyings(struct bc_writer *This, const struct bwriter_shader *shader) {
703 DWORD i;
704 DWORD usage, usage_idx, writemask, regnum;
706 for(i = 0; i < shader->num_outputs; i++) {
707 if(!shader->outputs[i].builtin) continue;
709 usage = shader->outputs[i].usage;
710 usage_idx = shader->outputs[i].usage_idx;
711 writemask = shader->outputs[i].writemask;
712 regnum = shader->outputs[i].regnum;
714 switch(usage) {
715 case BWRITERDECLUSAGE_POSITION:
716 case BWRITERDECLUSAGE_POSITIONT:
717 if(usage_idx > 0) {
718 WARN("dcl_position%u not supported in sm 1/2 shaders\n", usage_idx);
719 return E_INVALIDARG;
721 TRACE("o%u is oPos\n", regnum);
722 This->oPos_regnum = regnum;
723 break;
725 case BWRITERDECLUSAGE_COLOR:
726 if(usage_idx > 1) {
727 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
728 return E_INVALIDARG;
730 if(writemask != BWRITERSP_WRITEMASK_ALL) {
731 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
732 return E_INVALIDARG;
734 TRACE("o%u is oD%u\n", regnum, usage_idx);
735 This->oD_regnum[usage_idx] = regnum;
736 break;
738 case BWRITERDECLUSAGE_TEXCOORD:
739 if(usage_idx >= 8) {
740 WARN("dcl_color%u not supported in sm 1/2 shaders\n", usage_idx);
741 return E_INVALIDARG;
743 if(writemask != (BWRITERSP_WRITEMASK_0) &&
744 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
745 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
746 writemask != (BWRITERSP_WRITEMASK_ALL)) {
747 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
748 return E_INVALIDARG;
750 TRACE("o%u is oT%u\n", regnum, usage_idx);
751 This->oT_regnum[usage_idx] = regnum;
752 break;
754 case BWRITERDECLUSAGE_PSIZE:
755 if(usage_idx > 0) {
756 WARN("dcl_psize%u not supported in sm 1/2 shaders\n", usage_idx);
757 return E_INVALIDARG;
759 TRACE("o%u writemask 0x%08x is oPts\n", regnum, writemask);
760 This->oPts_regnum = regnum;
761 This->oPts_mask = writemask;
762 break;
764 case BWRITERDECLUSAGE_FOG:
765 if(usage_idx > 0) {
766 WARN("dcl_fog%u not supported in sm 1 shaders\n", usage_idx);
767 return E_INVALIDARG;
769 if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
770 writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
771 WARN("Unsupported fog writemask\n");
772 return E_INVALIDARG;
774 TRACE("o%u writemask 0x%08x is oFog\n", regnum, writemask);
775 This->oFog_regnum = regnum;
776 This->oFog_mask = writemask;
777 break;
779 default:
780 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
781 return E_INVALIDARG;
785 return S_OK;
788 static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
789 HRESULT hr;
791 if(shader->num_ci || shader->num_cb) {
792 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
793 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
794 This->state = E_INVALIDARG;
795 return;
798 hr = vs_find_builtin_varyings(This, shader);
799 if(FAILED(hr)) {
800 This->state = hr;
801 return;
804 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
805 write_constF(shader, buffer, FALSE);
808 static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
809 const struct bwriter_shader *shader,
810 DWORD texcoords) {
811 DWORD i;
812 DWORD usage, usage_idx, writemask, regnum;
814 This->v_regnum[0] = -1; This->v_regnum[1] = -1;
815 for(i = 0; i < 8; i++) This->t_regnum[i] = -1;
817 for(i = 0; i < shader->num_inputs; i++) {
818 if(!shader->inputs[i].builtin) continue;
820 usage = shader->inputs[i].usage;
821 usage_idx = shader->inputs[i].usage_idx;
822 writemask = shader->inputs[i].writemask;
823 regnum = shader->inputs[i].regnum;
825 switch(usage) {
826 case BWRITERDECLUSAGE_COLOR:
827 if(usage_idx > 1) {
828 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
829 return E_INVALIDARG;
831 if(writemask != BWRITERSP_WRITEMASK_ALL) {
832 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
833 return E_INVALIDARG;
835 TRACE("v%u is v%u\n", regnum, usage_idx);
836 This->v_regnum[usage_idx] = regnum;
837 break;
839 case BWRITERDECLUSAGE_TEXCOORD:
840 if(usage_idx > texcoords) {
841 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
842 return E_INVALIDARG;
844 if(writemask != (BWRITERSP_WRITEMASK_0) &&
845 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
846 writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
847 writemask != (BWRITERSP_WRITEMASK_ALL)) {
848 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
849 } else {
850 writemask = BWRITERSP_WRITEMASK_ALL;
852 TRACE("v%u is t%u\n", regnum, usage_idx);
853 This->t_regnum[usage_idx] = regnum;
854 break;
856 default:
857 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
858 return E_INVALIDARG;
862 return S_OK;
865 static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
866 HRESULT hr;
868 /* First check the constants and varyings, and complain if unsupported things are used */
869 if(shader->num_ci || shader->num_cb) {
870 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
871 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
872 This->state = E_INVALIDARG;
873 return;
876 hr = find_ps_builtin_semantics(This, shader, 4);
877 if(FAILED(hr)) {
878 This->state = hr;
879 return;
882 write_constF(shader, buffer, FALSE);
885 static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
886 HRESULT hr;
888 /* First check the constants and varyings, and complain if unsupported things are used */
889 if(shader->num_ci || shader->num_cb) {
890 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
891 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
892 This->state = E_INVALIDARG;
893 return;
895 hr = find_ps_builtin_semantics(This, shader, 6);
896 if(FAILED(hr)) {
897 This->state = hr;
898 return;
901 write_constF(shader, buffer, FALSE);
904 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
905 put_dword(buffer, D3DSIO_END);
908 static DWORD map_vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
909 DWORD i;
911 *has_components = TRUE;
912 if(regnum == This->oPos_regnum) {
913 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POSITION );
915 if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
916 *has_components = FALSE;
917 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_FOG ) | D3DSP_WRITEMASK_ALL;
919 if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
920 *has_components = FALSE;
921 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POINT_SIZE ) | D3DSP_WRITEMASK_ALL;
923 for(i = 0; i < 2; i++) {
924 if(regnum == This->oD_regnum[i]) {
925 return d3dsp_register( D3DSPR_ATTROUT, i );
928 for(i = 0; i < 8; i++) {
929 if(regnum == This->oT_regnum[i]) {
930 return d3dsp_register( D3DSPR_TEXCRDOUT, i );
934 /* The varying must be undeclared - if an unsupported varying was declared,
935 * the vs_find_builtin_varyings function would have caught it and this code
936 * would not run */
937 WARN("Undeclared varying %u\n", regnum);
938 This->state = E_INVALIDARG;
939 return -1;
942 static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
943 struct bytecode_buffer *buffer,
944 DWORD shift, DWORD mod) {
945 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
946 DWORD has_wmask;
948 if(reg->rel_reg) {
949 WARN("Relative addressing not supported for destination registers\n");
950 This->state = E_INVALIDARG;
951 return;
954 switch(reg->type) {
955 case BWRITERSPR_OUTPUT:
956 token |= map_vs_output(This, reg->regnum, reg->u.writemask, &has_wmask);
957 break;
959 case BWRITERSPR_RASTOUT:
960 case BWRITERSPR_ATTROUT:
961 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
962 * but are unexpected. If we hit this path it might be due to an error.
964 FIXME("Unexpected register type %u\n", reg->type);
965 /* drop through */
966 case BWRITERSPR_INPUT:
967 case BWRITERSPR_TEMP:
968 case BWRITERSPR_CONST:
969 token |= d3dsp_register( reg->type, reg->regnum );
970 has_wmask = TRUE;
971 break;
973 case BWRITERSPR_ADDR:
974 if(reg->regnum != 0) {
975 WARN("Only a0 exists\n");
976 This->state = E_INVALIDARG;
977 return;
979 token |= d3dsp_register( D3DSPR_ADDR, 0 );
980 has_wmask = TRUE;
981 break;
983 case BWRITERSPR_PREDICATE:
984 if (This->shader->major_version != 2 || This->shader->minor_version != 1)
986 WARN("Predicate register is allowed only in vs_2_x\n");
987 This->state = E_INVALIDARG;
988 return;
990 if(reg->regnum != 0) {
991 WARN("Only predicate register p0 exists\n");
992 This->state = E_INVALIDARG;
993 return;
995 token |= d3dsp_register( D3DSPR_PREDICATE, 0 );
996 has_wmask = TRUE;
997 break;
999 default:
1000 WARN("Invalid register type for 1.x-2.x vertex shader\n");
1001 This->state = E_INVALIDARG;
1002 return;
1005 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
1006 * into the bytecode and since the compiler doesn't do such checks write them
1007 * (the checks are done by the undocumented shader validator)
1009 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1010 token |= d3d9_dstmod(mod);
1012 if(has_wmask) {
1013 token |= d3d9_writemask(reg->u.writemask);
1015 put_dword(buffer, token);
1018 static void vs_1_x_srcreg(struct bc_writer *This, const struct shader_reg *reg,
1019 struct bytecode_buffer *buffer) {
1020 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1021 DWORD has_swizzle;
1022 DWORD component;
1024 switch(reg->type) {
1025 case BWRITERSPR_OUTPUT:
1026 /* Map the swizzle to a writemask, the format expected
1027 by map_vs_output
1029 switch(reg->u.swizzle) {
1030 case BWRITERVS_SWIZZLE_X:
1031 component = BWRITERSP_WRITEMASK_0;
1032 break;
1033 case BWRITERVS_SWIZZLE_Y:
1034 component = BWRITERSP_WRITEMASK_1;
1035 break;
1036 case BWRITERVS_SWIZZLE_Z:
1037 component = BWRITERSP_WRITEMASK_2;
1038 break;
1039 case BWRITERVS_SWIZZLE_W:
1040 component = BWRITERSP_WRITEMASK_3;
1041 break;
1042 default:
1043 component = 0;
1045 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
1046 break;
1048 case BWRITERSPR_RASTOUT:
1049 case BWRITERSPR_ATTROUT:
1050 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1051 * but are unexpected. If we hit this path it might be due to an error.
1053 FIXME("Unexpected register type %u\n", reg->type);
1054 /* drop through */
1055 case BWRITERSPR_INPUT:
1056 case BWRITERSPR_TEMP:
1057 case BWRITERSPR_CONST:
1058 case BWRITERSPR_ADDR:
1059 token |= d3dsp_register( reg->type, reg->regnum );
1060 if(reg->rel_reg) {
1061 if(reg->rel_reg->type != BWRITERSPR_ADDR ||
1062 reg->rel_reg->regnum != 0 ||
1063 reg->rel_reg->u.swizzle != BWRITERVS_SWIZZLE_X) {
1064 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
1065 This->state = E_INVALIDARG;
1066 return;
1068 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1070 break;
1072 default:
1073 WARN("Invalid register type for 1.x vshader\n");
1074 This->state = E_INVALIDARG;
1075 return;
1078 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1080 token |= d3d9_srcmod(reg->srcmod);
1081 put_dword(buffer, token);
1084 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
1085 struct bytecode_buffer *buffer){
1086 unsigned int i;
1087 if(instr->has_predicate){
1088 This->funcs->srcreg(This, &instr->predicate, buffer);
1090 for(i = 0; i < instr->num_srcs; i++){
1091 This->funcs->srcreg(This, &instr->src[i], buffer);
1095 static DWORD map_ps13_temp(struct bc_writer *This, const struct shader_reg *reg) {
1096 if(reg->regnum == T0_REG) {
1097 return d3dsp_register( D3DSPR_TEXTURE, 0 );
1098 } else if(reg->regnum == T1_REG) {
1099 return d3dsp_register( D3DSPR_TEXTURE, 1 );
1100 } else if(reg->regnum == T2_REG) {
1101 return d3dsp_register( D3DSPR_TEXTURE, 2 );
1102 } else if(reg->regnum == T3_REG) {
1103 return d3dsp_register( D3DSPR_TEXTURE, 3 );
1104 } else {
1105 return d3dsp_register( D3DSPR_TEMP, reg->regnum );
1109 static DWORD map_ps_input(struct bc_writer *This,
1110 const struct shader_reg *reg) {
1111 DWORD i;
1112 /* Map color interpolators */
1113 for(i = 0; i < 2; i++) {
1114 if(reg->regnum == This->v_regnum[i]) {
1115 return d3dsp_register( D3DSPR_INPUT, i );
1118 for(i = 0; i < 8; i++) {
1119 if(reg->regnum == This->t_regnum[i]) {
1120 return d3dsp_register( D3DSPR_TEXTURE, i );
1124 WARN("Invalid ps 1/2 varying\n");
1125 This->state = E_INVALIDARG;
1126 return 0;
1129 static void ps_1_0123_srcreg(struct bc_writer *This, const struct shader_reg *reg,
1130 struct bytecode_buffer *buffer) {
1131 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1132 if(reg->rel_reg) {
1133 WARN("Relative addressing not supported in <= ps_3_0\n");
1134 This->state = E_INVALIDARG;
1135 return;
1138 switch(reg->type) {
1139 case BWRITERSPR_INPUT:
1140 token |= map_ps_input(This, reg);
1141 break;
1143 /* Take care about the texture temporaries. There's a problem: They aren't
1144 * declared anywhere, so we can only hardcode the values that are used
1145 * to map ps_1_3 shaders to the common shader structure
1147 case BWRITERSPR_TEMP:
1148 token |= map_ps13_temp(This, reg);
1149 break;
1151 case BWRITERSPR_CONST: /* Can be mapped 1:1 */
1152 token |= d3dsp_register( reg->type, reg->regnum );
1153 break;
1155 default:
1156 WARN("Invalid register type for <= ps_1_3 shader\n");
1157 This->state = E_INVALIDARG;
1158 return;
1161 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1163 if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW ||
1164 reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
1165 reg->srcmod == BWRITERSPSM_NOT) {
1166 WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
1167 This->state = E_INVALIDARG;
1168 return;
1170 token |= d3d9_srcmod(reg->srcmod);
1171 put_dword(buffer, token);
1174 static void ps_1_0123_dstreg(struct bc_writer *This, const struct shader_reg *reg,
1175 struct bytecode_buffer *buffer,
1176 DWORD shift, DWORD mod) {
1177 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1179 if(reg->rel_reg) {
1180 WARN("Relative addressing not supported for destination registers\n");
1181 This->state = E_INVALIDARG;
1182 return;
1185 switch(reg->type) {
1186 case BWRITERSPR_TEMP:
1187 token |= map_ps13_temp(This, reg);
1188 break;
1190 /* texkill uses the input register as a destination parameter */
1191 case BWRITERSPR_INPUT:
1192 token |= map_ps_input(This, reg);
1193 break;
1195 default:
1196 WARN("Invalid dest register type for 1.x pshader\n");
1197 This->state = E_INVALIDARG;
1198 return;
1201 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1202 token |= d3d9_dstmod(mod);
1204 token |= d3d9_writemask(reg->u.writemask);
1205 put_dword(buffer, token);
1208 /* The length of an instruction consists of the destination register (if any),
1209 * the number of source registers, the number of address registers used for
1210 * indirect addressing, and optionally the predicate register
1212 static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts) {
1213 unsigned int i;
1214 DWORD ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
1216 if(dsts){
1217 if(instr->dst.rel_reg) ret++;
1219 for(i = 0; i < srcs; i++) {
1220 if(instr->src[i].rel_reg) ret++;
1222 return ret;
1225 static void sm_1_x_opcode(struct bc_writer *This,
1226 const struct instruction *instr,
1227 DWORD token, struct bytecode_buffer *buffer) {
1228 /* In sm_1_x instruction length isn't encoded */
1229 if(instr->coissue){
1230 token |= D3DSI_COISSUE;
1232 put_dword(buffer, token);
1235 static void instr_handler(struct bc_writer *This,
1236 const struct instruction *instr,
1237 struct bytecode_buffer *buffer) {
1238 DWORD token = d3d9_opcode(instr->opcode);
1240 This->funcs->opcode(This, instr, token, buffer);
1241 if(instr->has_dst) This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1242 write_srcregs(This, instr, buffer);
1245 static const struct instr_handler_table vs_1_x_handlers[] = {
1246 {BWRITERSIO_ADD, instr_handler},
1247 {BWRITERSIO_NOP, instr_handler},
1248 {BWRITERSIO_MOV, instr_handler},
1249 {BWRITERSIO_SUB, instr_handler},
1250 {BWRITERSIO_MAD, instr_handler},
1251 {BWRITERSIO_MUL, instr_handler},
1252 {BWRITERSIO_RCP, instr_handler},
1253 {BWRITERSIO_RSQ, instr_handler},
1254 {BWRITERSIO_DP3, instr_handler},
1255 {BWRITERSIO_DP4, instr_handler},
1256 {BWRITERSIO_MIN, instr_handler},
1257 {BWRITERSIO_MAX, instr_handler},
1258 {BWRITERSIO_SLT, instr_handler},
1259 {BWRITERSIO_SGE, instr_handler},
1260 {BWRITERSIO_EXP, instr_handler},
1261 {BWRITERSIO_LOG, instr_handler},
1262 {BWRITERSIO_EXPP, instr_handler},
1263 {BWRITERSIO_LOGP, instr_handler},
1264 {BWRITERSIO_DST, instr_handler},
1265 {BWRITERSIO_FRC, instr_handler},
1266 {BWRITERSIO_M4x4, instr_handler},
1267 {BWRITERSIO_M4x3, instr_handler},
1268 {BWRITERSIO_M3x4, instr_handler},
1269 {BWRITERSIO_M3x3, instr_handler},
1270 {BWRITERSIO_M3x2, instr_handler},
1271 {BWRITERSIO_LIT, instr_handler},
1273 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
1274 the end of the list */
1277 static const struct bytecode_backend vs_1_x_backend = {
1278 vs_1_x_header,
1279 end,
1280 vs_1_x_srcreg,
1281 vs_12_dstreg,
1282 sm_1_x_opcode,
1283 vs_1_x_handlers
1286 static void instr_ps_1_0123_texld(struct bc_writer *This,
1287 const struct instruction *instr,
1288 struct bytecode_buffer *buffer) {
1289 DWORD idx;
1290 struct shader_reg reg;
1291 DWORD swizzlemask;
1293 if(instr->src[1].type != BWRITERSPR_SAMPLER ||
1294 instr->src[1].regnum > 3) {
1295 WARN("Unsupported sampler type %u regnum %u\n",
1296 instr->src[1].type, instr->src[1].regnum);
1297 This->state = E_INVALIDARG;
1298 return;
1299 } else if(instr->dst.type != BWRITERSPR_TEMP) {
1300 WARN("Can only sample into a temp register\n");
1301 This->state = E_INVALIDARG;
1302 return;
1305 idx = instr->src[1].regnum;
1306 if((idx == 0 && instr->dst.regnum != T0_REG) ||
1307 (idx == 1 && instr->dst.regnum != T1_REG) ||
1308 (idx == 2 && instr->dst.regnum != T2_REG) ||
1309 (idx == 3 && instr->dst.regnum != T3_REG)) {
1310 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n",
1311 idx, instr->dst.regnum);
1312 This->state = E_INVALIDARG;
1313 return;
1315 if(instr->src[0].type == BWRITERSPR_INPUT) {
1316 /* A simple non-dependent read tex instruction */
1317 if(instr->src[0].regnum != This->t_regnum[idx]) {
1318 WARN("Cannot sample from s%u with texture address data from interpolator %u\n",
1319 idx, instr->src[0].regnum);
1320 This->state = E_INVALIDARG;
1321 return;
1323 This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1325 /* map the temp dstreg to the ps_1_3 texture temporary register */
1326 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1327 } else if(instr->src[0].type == BWRITERSPR_TEMP) {
1329 swizzlemask = 3 | (3 << 2) | (3 << 4);
1330 if((instr->src[0].u.swizzle & swizzlemask) == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z)) {
1331 TRACE("writing texreg2rgb\n");
1332 This->funcs->opcode(This, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
1333 } else if(instr->src[0].u.swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)) {
1334 TRACE("writing texreg2ar\n");
1335 This->funcs->opcode(This, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
1336 } else if(instr->src[0].u.swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)) {
1337 TRACE("writing texreg2gb\n");
1338 This->funcs->opcode(This, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
1339 } else {
1340 WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].u.swizzle);
1341 This->state = E_INVALIDARG;
1342 return;
1345 /* Dst and src reg can be mapped normally. Both registers are temporary registers in the
1346 * source shader and have to be mapped to the temporary form of the texture registers. However,
1347 * the src reg doesn't have a swizzle
1349 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1350 reg = instr->src[0];
1351 reg.u.swizzle = BWRITERVS_NOSWIZZLE;
1352 This->funcs->srcreg(This, &reg, buffer);
1353 } else {
1354 WARN("Invalid address data source register\n");
1355 This->state = E_INVALIDARG;
1356 return;
1360 static void instr_ps_1_0123_mov(struct bc_writer *This,
1361 const struct instruction *instr,
1362 struct bytecode_buffer *buffer) {
1363 DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1365 if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
1366 if((instr->dst.regnum == T0_REG && instr->src[0].regnum == This->t_regnum[0]) ||
1367 (instr->dst.regnum == T1_REG && instr->src[0].regnum == This->t_regnum[1]) ||
1368 (instr->dst.regnum == T2_REG && instr->src[0].regnum == This->t_regnum[2]) ||
1369 (instr->dst.regnum == T3_REG && instr->src[0].regnum == This->t_regnum[3])) {
1370 if(instr->dstmod & BWRITERSPDM_SATURATE) {
1371 This->funcs->opcode(This, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
1372 /* Remove the SATURATE flag, it's implicit to the instruction */
1373 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
1374 return;
1375 } else {
1376 WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
1377 This->state = E_INVALIDARG;
1378 return;
1380 } else if(instr->src[0].regnum == This->v_regnum[0] ||
1381 instr->src[0].regnum == This->v_regnum[1]) {
1382 /* Handled by the normal mov below. Just drop out of the if condition */
1383 } else {
1384 WARN("Unsupported varying -> temp mov in <= ps_1_3\n");
1385 This->state = E_INVALIDARG;
1386 return;
1390 This->funcs->opcode(This, instr, token, buffer);
1391 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1392 This->funcs->srcreg(This, &instr->src[0], buffer);
1395 static const struct instr_handler_table ps_1_0123_handlers[] = {
1396 {BWRITERSIO_ADD, instr_handler},
1397 {BWRITERSIO_NOP, instr_handler},
1398 {BWRITERSIO_MOV, instr_ps_1_0123_mov},
1399 {BWRITERSIO_SUB, instr_handler},
1400 {BWRITERSIO_MAD, instr_handler},
1401 {BWRITERSIO_MUL, instr_handler},
1402 {BWRITERSIO_DP3, instr_handler},
1403 {BWRITERSIO_DP4, instr_handler},
1404 {BWRITERSIO_LRP, instr_handler},
1406 /* pshader instructions */
1407 {BWRITERSIO_CND, instr_handler},
1408 {BWRITERSIO_CMP, instr_handler},
1409 {BWRITERSIO_TEXKILL, instr_handler},
1410 {BWRITERSIO_TEX, instr_ps_1_0123_texld},
1411 {BWRITERSIO_TEXBEM, instr_handler},
1412 {BWRITERSIO_TEXBEML, instr_handler},
1413 {BWRITERSIO_TEXM3x2PAD, instr_handler},
1414 {BWRITERSIO_TEXM3x3PAD, instr_handler},
1415 {BWRITERSIO_TEXM3x3SPEC, instr_handler},
1416 {BWRITERSIO_TEXM3x3VSPEC, instr_handler},
1417 {BWRITERSIO_TEXM3x3TEX, instr_handler},
1418 {BWRITERSIO_TEXM3x3, instr_handler},
1419 {BWRITERSIO_TEXM3x2DEPTH, instr_handler},
1420 {BWRITERSIO_TEXM3x2TEX, instr_handler},
1421 {BWRITERSIO_TEXDP3, instr_handler},
1422 {BWRITERSIO_TEXDP3TEX, instr_handler},
1423 {BWRITERSIO_END, NULL},
1426 static const struct bytecode_backend ps_1_0123_backend = {
1427 ps_1_x_header,
1428 end,
1429 ps_1_0123_srcreg,
1430 ps_1_0123_dstreg,
1431 sm_1_x_opcode,
1432 ps_1_0123_handlers
1435 static void ps_1_4_srcreg(struct bc_writer *This, const struct shader_reg *reg,
1436 struct bytecode_buffer *buffer) {
1437 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1438 if(reg->rel_reg) {
1439 WARN("Relative addressing not supported in <= ps_3_0\n");
1440 This->state = E_INVALIDARG;
1441 return;
1444 switch(reg->type) {
1445 case BWRITERSPR_INPUT:
1446 token |= map_ps_input(This, reg);
1447 break;
1449 /* Can be mapped 1:1 */
1450 case BWRITERSPR_TEMP:
1451 case BWRITERSPR_CONST:
1452 token |= d3dsp_register( reg->type, reg->regnum );
1453 break;
1455 default:
1456 WARN("Invalid register type for ps_1_4 shader\n");
1457 This->state = E_INVALIDARG;
1458 return;
1461 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1463 if(reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
1464 reg->srcmod == BWRITERSPSM_NOT) {
1465 WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
1466 This->state = E_INVALIDARG;
1467 return;
1469 token |= d3d9_srcmod(reg->srcmod);
1470 put_dword(buffer, token);
1473 static void ps_1_4_dstreg(struct bc_writer *This, const struct shader_reg *reg,
1474 struct bytecode_buffer *buffer,
1475 DWORD shift, DWORD mod) {
1476 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1478 if(reg->rel_reg) {
1479 WARN("Relative addressing not supported for destination registers\n");
1480 This->state = E_INVALIDARG;
1481 return;
1484 switch(reg->type) {
1485 case BWRITERSPR_TEMP: /* 1:1 mapping */
1486 token |= d3dsp_register( reg->type, reg->regnum );
1487 break;
1489 /* For texkill */
1490 case BWRITERSPR_INPUT:
1491 token |= map_ps_input(This, reg);
1492 break;
1494 default:
1495 WARN("Invalid dest register type for 1.x pshader\n");
1496 This->state = E_INVALIDARG;
1497 return;
1500 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1501 token |= d3d9_dstmod(mod);
1503 token |= d3d9_writemask(reg->u.writemask);
1504 put_dword(buffer, token);
1507 static void instr_ps_1_4_mov(struct bc_writer *This,
1508 const struct instruction *instr,
1509 struct bytecode_buffer *buffer) {
1510 DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1512 if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
1513 if(instr->src[0].regnum == This->t_regnum[0] ||
1514 instr->src[0].regnum == This->t_regnum[1] ||
1515 instr->src[0].regnum == This->t_regnum[2] ||
1516 instr->src[0].regnum == This->t_regnum[3] ||
1517 instr->src[0].regnum == This->t_regnum[4] ||
1518 instr->src[0].regnum == This->t_regnum[5]) {
1519 /* Similar to a regular mov, but a different opcode */
1520 token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
1521 } else if(instr->src[0].regnum == This->v_regnum[0] ||
1522 instr->src[0].regnum == This->v_regnum[1]) {
1523 /* Handled by the normal mov below. Just drop out of the if condition */
1524 } else {
1525 WARN("Unsupported varying -> temp mov in ps_1_4\n");
1526 This->state = E_INVALIDARG;
1527 return;
1531 This->funcs->opcode(This, instr, token, buffer);
1532 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1533 This->funcs->srcreg(This, &instr->src[0], buffer);
1536 static void instr_ps_1_4_texld(struct bc_writer *This,
1537 const struct instruction *instr,
1538 struct bytecode_buffer *buffer) {
1539 if(instr->src[1].type != BWRITERSPR_SAMPLER ||
1540 instr->src[1].regnum > 5) {
1541 WARN("Unsupported sampler type %u regnum %u\n",
1542 instr->src[1].type, instr->src[1].regnum);
1543 This->state = E_INVALIDARG;
1544 return;
1545 } else if(instr->dst.type != BWRITERSPR_TEMP) {
1546 WARN("Can only sample into a temp register\n");
1547 This->state = E_INVALIDARG;
1548 return;
1551 if(instr->src[1].regnum != instr->dst.regnum) {
1552 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4\n",
1553 instr->src[1].regnum, instr->dst.regnum);
1554 This->state = E_INVALIDARG;
1555 return;
1558 This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1559 This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
1560 This->funcs->srcreg(This, &instr->src[0], buffer);
1563 static const struct instr_handler_table ps_1_4_handlers[] = {
1564 {BWRITERSIO_ADD, instr_handler},
1565 {BWRITERSIO_NOP, instr_handler},
1566 {BWRITERSIO_MOV, instr_ps_1_4_mov},
1567 {BWRITERSIO_SUB, instr_handler},
1568 {BWRITERSIO_MAD, instr_handler},
1569 {BWRITERSIO_MUL, instr_handler},
1570 {BWRITERSIO_DP3, instr_handler},
1571 {BWRITERSIO_DP4, instr_handler},
1572 {BWRITERSIO_LRP, instr_handler},
1574 /* pshader instructions */
1575 {BWRITERSIO_CND, instr_handler},
1576 {BWRITERSIO_CMP, instr_handler},
1577 {BWRITERSIO_TEXKILL, instr_handler},
1578 {BWRITERSIO_TEX, instr_ps_1_4_texld},
1579 {BWRITERSIO_TEXDEPTH, instr_handler},
1580 {BWRITERSIO_BEM, instr_handler},
1582 {BWRITERSIO_PHASE, instr_handler},
1583 {BWRITERSIO_END, NULL},
1586 static const struct bytecode_backend ps_1_4_backend = {
1587 ps_1_4_header,
1588 end,
1589 ps_1_4_srcreg,
1590 ps_1_4_dstreg,
1591 sm_1_x_opcode,
1592 ps_1_4_handlers
1595 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1596 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
1599 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1600 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
1603 static void vs_2_header(struct bc_writer *This,
1604 const struct bwriter_shader *shader,
1605 struct bytecode_buffer *buffer) {
1606 HRESULT hr;
1608 hr = vs_find_builtin_varyings(This, shader);
1609 if(FAILED(hr)) {
1610 This->state = hr;
1611 return;
1614 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1615 write_constF(shader, buffer, TRUE);
1616 write_constB(shader, buffer, TRUE);
1617 write_constI(shader, buffer, TRUE);
1620 static void vs_2_srcreg(struct bc_writer *This,
1621 const struct shader_reg *reg,
1622 struct bytecode_buffer *buffer) {
1623 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1624 DWORD has_swizzle;
1625 DWORD component;
1626 DWORD d3d9reg;
1628 switch(reg->type) {
1629 case BWRITERSPR_OUTPUT:
1630 /* Map the swizzle to a writemask, the format expected
1631 by map_vs_output
1633 switch(reg->u.swizzle) {
1634 case BWRITERVS_SWIZZLE_X:
1635 component = BWRITERSP_WRITEMASK_0;
1636 break;
1637 case BWRITERVS_SWIZZLE_Y:
1638 component = BWRITERSP_WRITEMASK_1;
1639 break;
1640 case BWRITERVS_SWIZZLE_Z:
1641 component = BWRITERSP_WRITEMASK_2;
1642 break;
1643 case BWRITERVS_SWIZZLE_W:
1644 component = BWRITERSP_WRITEMASK_3;
1645 break;
1646 default:
1647 component = 0;
1649 token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
1650 break;
1652 case BWRITERSPR_RASTOUT:
1653 case BWRITERSPR_ATTROUT:
1654 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1655 * but are unexpected. If we hit this path it might be due to an error.
1657 FIXME("Unexpected register type %u\n", reg->type);
1658 /* drop through */
1659 case BWRITERSPR_INPUT:
1660 case BWRITERSPR_TEMP:
1661 case BWRITERSPR_CONST:
1662 case BWRITERSPR_ADDR:
1663 case BWRITERSPR_CONSTINT:
1664 case BWRITERSPR_CONSTBOOL:
1665 case BWRITERSPR_LABEL:
1666 d3d9reg = d3d9_register(reg->type);
1667 token |= d3dsp_register( d3d9reg, reg->regnum );
1668 break;
1670 case BWRITERSPR_LOOP:
1671 if(reg->regnum != 0) {
1672 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
1673 This->state = E_INVALIDARG;
1674 return;
1676 token |= d3dsp_register( D3DSPR_LOOP, 0 );
1677 break;
1679 case BWRITERSPR_PREDICATE:
1680 if (This->shader->major_version != 2 || This->shader->minor_version != 1)
1682 WARN("Predicate register is allowed only in vs_2_x\n");
1683 This->state = E_INVALIDARG;
1684 return;
1686 if(reg->regnum > 0) {
1687 WARN("Only predicate register 0 is supported\n");
1688 This->state = E_INVALIDARG;
1689 return;
1691 token |= d3dsp_register( D3DSPR_PREDICATE, 0 );
1692 break;
1694 default:
1695 WARN("Invalid register type for 2.0 vshader\n");
1696 This->state = E_INVALIDARG;
1697 return;
1700 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1702 token |= d3d9_srcmod(reg->srcmod);
1704 if(reg->rel_reg)
1705 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1707 put_dword(buffer, token);
1709 /* vs_2_0 and newer write the register containing the index explicitly in the
1710 * binary code
1712 if(token & D3DVS_ADDRMODE_RELATIVE)
1713 vs_2_srcreg(This, reg->rel_reg, buffer);
1716 static void sm_2_opcode(struct bc_writer *This,
1717 const struct instruction *instr,
1718 DWORD token, struct bytecode_buffer *buffer) {
1719 /* From sm 2 onwards instruction length is encoded in the opcode field */
1720 int dsts = instr->has_dst ? 1 : 0;
1721 token |= instrlen(instr, instr->num_srcs, dsts) << D3DSI_INSTLENGTH_SHIFT;
1722 if(instr->comptype)
1723 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1724 if(instr->has_predicate)
1725 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1726 put_dword(buffer,token);
1729 static const struct instr_handler_table vs_2_0_handlers[] = {
1730 {BWRITERSIO_ADD, instr_handler},
1731 {BWRITERSIO_NOP, instr_handler},
1732 {BWRITERSIO_MOV, instr_handler},
1733 {BWRITERSIO_SUB, instr_handler},
1734 {BWRITERSIO_MAD, instr_handler},
1735 {BWRITERSIO_MUL, instr_handler},
1736 {BWRITERSIO_RCP, instr_handler},
1737 {BWRITERSIO_RSQ, instr_handler},
1738 {BWRITERSIO_DP3, instr_handler},
1739 {BWRITERSIO_DP4, instr_handler},
1740 {BWRITERSIO_MIN, instr_handler},
1741 {BWRITERSIO_MAX, instr_handler},
1742 {BWRITERSIO_SLT, instr_handler},
1743 {BWRITERSIO_SGE, instr_handler},
1744 {BWRITERSIO_ABS, instr_handler},
1745 {BWRITERSIO_EXP, instr_handler},
1746 {BWRITERSIO_LOG, instr_handler},
1747 {BWRITERSIO_EXPP, instr_handler},
1748 {BWRITERSIO_LOGP, instr_handler},
1749 {BWRITERSIO_DST, instr_handler},
1750 {BWRITERSIO_LRP, instr_handler},
1751 {BWRITERSIO_FRC, instr_handler},
1752 {BWRITERSIO_CRS, instr_handler},
1753 {BWRITERSIO_SGN, instr_handler},
1754 {BWRITERSIO_NRM, instr_handler},
1755 {BWRITERSIO_SINCOS, instr_handler},
1756 {BWRITERSIO_M4x4, instr_handler},
1757 {BWRITERSIO_M4x3, instr_handler},
1758 {BWRITERSIO_M3x4, instr_handler},
1759 {BWRITERSIO_M3x3, instr_handler},
1760 {BWRITERSIO_M3x2, instr_handler},
1761 {BWRITERSIO_LIT, instr_handler},
1762 {BWRITERSIO_POW, instr_handler},
1763 {BWRITERSIO_MOVA, instr_handler},
1765 {BWRITERSIO_CALL, instr_handler},
1766 {BWRITERSIO_CALLNZ, instr_handler},
1767 {BWRITERSIO_REP, instr_handler},
1768 {BWRITERSIO_ENDREP, instr_handler},
1769 {BWRITERSIO_IF, instr_handler},
1770 {BWRITERSIO_LABEL, instr_handler},
1771 {BWRITERSIO_ELSE, instr_handler},
1772 {BWRITERSIO_ENDIF, instr_handler},
1773 {BWRITERSIO_LOOP, instr_handler},
1774 {BWRITERSIO_RET, instr_handler},
1775 {BWRITERSIO_ENDLOOP, instr_handler},
1777 {BWRITERSIO_END, NULL},
1780 static const struct bytecode_backend vs_2_0_backend = {
1781 vs_2_header,
1782 end,
1783 vs_2_srcreg,
1784 vs_12_dstreg,
1785 sm_2_opcode,
1786 vs_2_0_handlers
1789 static const struct instr_handler_table vs_2_x_handlers[] = {
1790 {BWRITERSIO_ADD, instr_handler},
1791 {BWRITERSIO_NOP, instr_handler},
1792 {BWRITERSIO_MOV, instr_handler},
1793 {BWRITERSIO_SUB, instr_handler},
1794 {BWRITERSIO_MAD, instr_handler},
1795 {BWRITERSIO_MUL, instr_handler},
1796 {BWRITERSIO_RCP, instr_handler},
1797 {BWRITERSIO_RSQ, instr_handler},
1798 {BWRITERSIO_DP3, instr_handler},
1799 {BWRITERSIO_DP4, instr_handler},
1800 {BWRITERSIO_MIN, instr_handler},
1801 {BWRITERSIO_MAX, instr_handler},
1802 {BWRITERSIO_SLT, instr_handler},
1803 {BWRITERSIO_SGE, instr_handler},
1804 {BWRITERSIO_ABS, instr_handler},
1805 {BWRITERSIO_EXP, instr_handler},
1806 {BWRITERSIO_LOG, instr_handler},
1807 {BWRITERSIO_EXPP, instr_handler},
1808 {BWRITERSIO_LOGP, instr_handler},
1809 {BWRITERSIO_DST, instr_handler},
1810 {BWRITERSIO_LRP, instr_handler},
1811 {BWRITERSIO_FRC, instr_handler},
1812 {BWRITERSIO_CRS, instr_handler},
1813 {BWRITERSIO_SGN, instr_handler},
1814 {BWRITERSIO_NRM, instr_handler},
1815 {BWRITERSIO_SINCOS, instr_handler},
1816 {BWRITERSIO_M4x4, instr_handler},
1817 {BWRITERSIO_M4x3, instr_handler},
1818 {BWRITERSIO_M3x4, instr_handler},
1819 {BWRITERSIO_M3x3, instr_handler},
1820 {BWRITERSIO_M3x2, instr_handler},
1821 {BWRITERSIO_LIT, instr_handler},
1822 {BWRITERSIO_POW, instr_handler},
1823 {BWRITERSIO_MOVA, instr_handler},
1825 {BWRITERSIO_CALL, instr_handler},
1826 {BWRITERSIO_CALLNZ, instr_handler},
1827 {BWRITERSIO_REP, instr_handler},
1828 {BWRITERSIO_ENDREP, instr_handler},
1829 {BWRITERSIO_IF, instr_handler},
1830 {BWRITERSIO_LABEL, instr_handler},
1831 {BWRITERSIO_IFC, instr_handler},
1832 {BWRITERSIO_ELSE, instr_handler},
1833 {BWRITERSIO_ENDIF, instr_handler},
1834 {BWRITERSIO_BREAK, instr_handler},
1835 {BWRITERSIO_BREAKC, instr_handler},
1836 {BWRITERSIO_LOOP, instr_handler},
1837 {BWRITERSIO_RET, instr_handler},
1838 {BWRITERSIO_ENDLOOP, instr_handler},
1840 {BWRITERSIO_SETP, instr_handler},
1841 {BWRITERSIO_BREAKP, instr_handler},
1843 {BWRITERSIO_END, NULL},
1846 static const struct bytecode_backend vs_2_x_backend = {
1847 vs_2_header,
1848 end,
1849 vs_2_srcreg,
1850 vs_12_dstreg,
1851 sm_2_opcode,
1852 vs_2_x_handlers
1855 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1856 DWORD i;
1857 DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1858 DWORD token;
1859 const DWORD reg = (1u << 31) | d3dsp_register( D3DSPR_SAMPLER, 0 ) | D3DSP_WRITEMASK_ALL;
1861 for(i = 0; i < shader->num_samplers; i++) {
1862 /* Write the DCL instruction */
1863 put_dword(buffer, instr_dcl);
1864 token = (1u << 31);
1865 /* Already shifted */
1866 token |= (d3d9_sampler(shader->samplers[i].type)) & D3DSP_TEXTURETYPE_MASK;
1867 put_dword(buffer, token);
1868 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1869 token |= d3d9_dstmod(shader->samplers[i].mod);
1870 put_dword(buffer, token);
1874 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1875 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1876 if(FAILED(hr)) {
1877 This->state = hr;
1878 return;
1881 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1882 write_samplers(shader, buffer);
1883 write_constF(shader, buffer, TRUE);
1884 write_constB(shader, buffer, TRUE);
1885 write_constI(shader, buffer, TRUE);
1888 static void ps_2_srcreg(struct bc_writer *This,
1889 const struct shader_reg *reg,
1890 struct bytecode_buffer *buffer) {
1891 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1892 DWORD d3d9reg;
1893 if(reg->rel_reg) {
1894 WARN("Relative addressing not supported in <= ps_3_0\n");
1895 This->state = E_INVALIDARG;
1896 return;
1899 switch(reg->type) {
1900 case BWRITERSPR_INPUT:
1901 token |= map_ps_input(This, reg);
1902 break;
1904 /* Can be mapped 1:1 */
1905 case BWRITERSPR_TEMP:
1906 case BWRITERSPR_CONST:
1907 case BWRITERSPR_COLOROUT:
1908 case BWRITERSPR_CONSTBOOL:
1909 case BWRITERSPR_CONSTINT:
1910 case BWRITERSPR_SAMPLER:
1911 case BWRITERSPR_LABEL:
1912 case BWRITERSPR_DEPTHOUT:
1913 d3d9reg = d3d9_register(reg->type);
1914 token |= d3dsp_register( d3d9reg, reg->regnum );
1915 break;
1917 case BWRITERSPR_PREDICATE:
1918 if (This->shader->minor_version == 0)
1920 WARN("Predicate register not supported in ps_2_0\n");
1921 This->state = E_INVALIDARG;
1923 if(reg->regnum) {
1924 WARN("Predicate register with regnum %u not supported\n",
1925 reg->regnum);
1926 This->state = E_INVALIDARG;
1928 token |= d3dsp_register( D3DSPR_PREDICATE, 0 );
1929 break;
1931 default:
1932 WARN("Invalid register type for ps_2_0 shader\n");
1933 This->state = E_INVALIDARG;
1934 return;
1937 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1939 token |= d3d9_srcmod(reg->srcmod);
1940 put_dword(buffer, token);
1943 static void ps_2_0_dstreg(struct bc_writer *This,
1944 const struct shader_reg *reg,
1945 struct bytecode_buffer *buffer,
1946 DWORD shift, DWORD mod) {
1947 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
1948 DWORD d3d9reg;
1950 if(reg->rel_reg) {
1951 WARN("Relative addressing not supported for destination registers\n");
1952 This->state = E_INVALIDARG;
1953 return;
1956 switch(reg->type) {
1957 case BWRITERSPR_TEMP: /* 1:1 mapping */
1958 case BWRITERSPR_COLOROUT:
1959 case BWRITERSPR_DEPTHOUT:
1960 d3d9reg = d3d9_register(reg->type);
1961 token |= d3dsp_register( d3d9reg, reg->regnum );
1962 break;
1964 case BWRITERSPR_PREDICATE:
1965 if (This->shader->minor_version == 0)
1967 WARN("Predicate register not supported in ps_2_0\n");
1968 This->state = E_INVALIDARG;
1970 token |= d3dsp_register( D3DSPR_PREDICATE, reg->regnum );
1971 break;
1973 /* texkill uses the input register as a destination parameter */
1974 case BWRITERSPR_INPUT:
1975 token |= map_ps_input(This, reg);
1976 break;
1978 default:
1979 WARN("Invalid dest register type for 2.x pshader\n");
1980 This->state = E_INVALIDARG;
1981 return;
1984 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1985 token |= d3d9_dstmod(mod);
1987 token |= d3d9_writemask(reg->u.writemask);
1988 put_dword(buffer, token);
1991 static const struct instr_handler_table ps_2_0_handlers[] = {
1992 {BWRITERSIO_ADD, instr_handler},
1993 {BWRITERSIO_NOP, instr_handler},
1994 {BWRITERSIO_MOV, instr_handler},
1995 {BWRITERSIO_SUB, instr_handler},
1996 {BWRITERSIO_MAD, instr_handler},
1997 {BWRITERSIO_MUL, instr_handler},
1998 {BWRITERSIO_RCP, instr_handler},
1999 {BWRITERSIO_RSQ, instr_handler},
2000 {BWRITERSIO_DP3, instr_handler},
2001 {BWRITERSIO_DP4, instr_handler},
2002 {BWRITERSIO_MIN, instr_handler},
2003 {BWRITERSIO_MAX, instr_handler},
2004 {BWRITERSIO_ABS, instr_handler},
2005 {BWRITERSIO_EXP, instr_handler},
2006 {BWRITERSIO_LOG, instr_handler},
2007 {BWRITERSIO_EXPP, instr_handler},
2008 {BWRITERSIO_LOGP, instr_handler},
2009 {BWRITERSIO_LRP, instr_handler},
2010 {BWRITERSIO_FRC, instr_handler},
2011 {BWRITERSIO_CRS, instr_handler},
2012 {BWRITERSIO_NRM, instr_handler},
2013 {BWRITERSIO_SINCOS, instr_handler},
2014 {BWRITERSIO_M4x4, instr_handler},
2015 {BWRITERSIO_M4x3, instr_handler},
2016 {BWRITERSIO_M3x4, instr_handler},
2017 {BWRITERSIO_M3x3, instr_handler},
2018 {BWRITERSIO_M3x2, instr_handler},
2019 {BWRITERSIO_POW, instr_handler},
2020 {BWRITERSIO_DP2ADD, instr_handler},
2021 {BWRITERSIO_CMP, instr_handler},
2023 {BWRITERSIO_TEX, instr_handler},
2024 {BWRITERSIO_TEXLDP, instr_handler},
2025 {BWRITERSIO_TEXLDB, instr_handler},
2026 {BWRITERSIO_TEXKILL, instr_handler},
2028 {BWRITERSIO_END, NULL},
2031 static const struct bytecode_backend ps_2_0_backend = {
2032 ps_2_header,
2033 end,
2034 ps_2_srcreg,
2035 ps_2_0_dstreg,
2036 sm_2_opcode,
2037 ps_2_0_handlers
2040 static const struct instr_handler_table ps_2_x_handlers[] = {
2041 {BWRITERSIO_ADD, instr_handler},
2042 {BWRITERSIO_NOP, instr_handler},
2043 {BWRITERSIO_MOV, instr_handler},
2044 {BWRITERSIO_SUB, instr_handler},
2045 {BWRITERSIO_MAD, instr_handler},
2046 {BWRITERSIO_MUL, instr_handler},
2047 {BWRITERSIO_RCP, instr_handler},
2048 {BWRITERSIO_RSQ, instr_handler},
2049 {BWRITERSIO_DP3, instr_handler},
2050 {BWRITERSIO_DP4, instr_handler},
2051 {BWRITERSIO_MIN, instr_handler},
2052 {BWRITERSIO_MAX, instr_handler},
2053 {BWRITERSIO_ABS, instr_handler},
2054 {BWRITERSIO_EXP, instr_handler},
2055 {BWRITERSIO_LOG, instr_handler},
2056 {BWRITERSIO_EXPP, instr_handler},
2057 {BWRITERSIO_LOGP, instr_handler},
2058 {BWRITERSIO_LRP, instr_handler},
2059 {BWRITERSIO_FRC, instr_handler},
2060 {BWRITERSIO_CRS, instr_handler},
2061 {BWRITERSIO_NRM, instr_handler},
2062 {BWRITERSIO_SINCOS, instr_handler},
2063 {BWRITERSIO_M4x4, instr_handler},
2064 {BWRITERSIO_M4x3, instr_handler},
2065 {BWRITERSIO_M3x4, instr_handler},
2066 {BWRITERSIO_M3x3, instr_handler},
2067 {BWRITERSIO_M3x2, instr_handler},
2068 {BWRITERSIO_POW, instr_handler},
2069 {BWRITERSIO_DP2ADD, instr_handler},
2070 {BWRITERSIO_CMP, instr_handler},
2072 {BWRITERSIO_CALL, instr_handler},
2073 {BWRITERSIO_CALLNZ, instr_handler},
2074 {BWRITERSIO_REP, instr_handler},
2075 {BWRITERSIO_ENDREP, instr_handler},
2076 {BWRITERSIO_IF, instr_handler},
2077 {BWRITERSIO_LABEL, instr_handler},
2078 {BWRITERSIO_IFC, instr_handler},
2079 {BWRITERSIO_ELSE, instr_handler},
2080 {BWRITERSIO_ENDIF, instr_handler},
2081 {BWRITERSIO_BREAK, instr_handler},
2082 {BWRITERSIO_BREAKC, instr_handler},
2083 {BWRITERSIO_RET, instr_handler},
2085 {BWRITERSIO_TEX, instr_handler},
2086 {BWRITERSIO_TEXLDP, instr_handler},
2087 {BWRITERSIO_TEXLDB, instr_handler},
2088 {BWRITERSIO_TEXKILL, instr_handler},
2089 {BWRITERSIO_DSX, instr_handler},
2090 {BWRITERSIO_DSY, instr_handler},
2092 {BWRITERSIO_SETP, instr_handler},
2093 {BWRITERSIO_BREAKP, instr_handler},
2095 {BWRITERSIO_TEXLDD, instr_handler},
2097 {BWRITERSIO_END, NULL},
2100 static const struct bytecode_backend ps_2_x_backend = {
2101 ps_2_header,
2102 end,
2103 ps_2_srcreg,
2104 ps_2_0_dstreg,
2105 sm_2_opcode,
2106 ps_2_x_handlers
2109 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
2110 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
2111 write_declarations(This, buffer, shader->outputs, shader->num_outputs, BWRITERSPR_OUTPUT);
2112 write_constF(shader, buffer, TRUE);
2113 write_constB(shader, buffer, TRUE);
2114 write_constI(shader, buffer, TRUE);
2115 write_samplers(shader, buffer);
2118 static void sm_3_srcreg(struct bc_writer *This,
2119 const struct shader_reg *reg,
2120 struct bytecode_buffer *buffer) {
2121 const struct bwriter_shader *shader = This->shader;
2122 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
2123 DWORD d3d9reg;
2125 d3d9reg = d3d9_register(reg->type);
2126 token |= d3dsp_register( d3d9reg, reg->regnum );
2127 token |= d3d9_swizzle(reg->u.swizzle) & D3DVS_SWIZZLE_MASK;
2128 token |= d3d9_srcmod(reg->srcmod);
2130 if(reg->rel_reg) {
2131 if (reg->type == BWRITERSPR_CONST && shader->type == ST_PIXEL)
2133 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
2134 This->state = E_INVALIDARG;
2135 return;
2138 if (((reg->rel_reg->type == BWRITERSPR_ADDR && shader->type == ST_VERTEX)
2139 || reg->rel_reg->type == BWRITERSPR_LOOP) && reg->rel_reg->regnum == 0)
2141 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2142 } else {
2143 WARN("Unsupported relative addressing register\n");
2144 This->state = E_INVALIDARG;
2145 return;
2149 put_dword(buffer, token);
2151 /* vs_2_0 and newer write the register containing the index explicitly in the
2152 * binary code
2154 if(token & D3DVS_ADDRMODE_RELATIVE) {
2155 sm_3_srcreg(This, reg->rel_reg, buffer);
2159 static void sm_3_dstreg(struct bc_writer *This,
2160 const struct shader_reg *reg,
2161 struct bytecode_buffer *buffer,
2162 DWORD shift, DWORD mod) {
2163 const struct bwriter_shader *shader = This->shader;
2164 DWORD token = (1u << 31); /* Bit 31 of registers is 1 */
2165 DWORD d3d9reg;
2167 if(reg->rel_reg) {
2168 if (shader->type == ST_VERTEX && reg->type == BWRITERSPR_OUTPUT)
2170 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2171 } else {
2172 WARN("Relative addressing not supported for this shader type or register type\n");
2173 This->state = E_INVALIDARG;
2174 return;
2178 d3d9reg = d3d9_register(reg->type);
2179 token |= d3dsp_register( d3d9reg, reg->regnum );
2180 token |= d3d9_dstmod(mod);
2181 token |= d3d9_writemask(reg->u.writemask);
2182 put_dword(buffer, token);
2184 /* vs_2_0 and newer write the register containing the index explicitly in the
2185 * binary code
2187 if(token & D3DVS_ADDRMODE_RELATIVE) {
2188 sm_3_srcreg(This, reg->rel_reg, buffer);
2192 static const struct instr_handler_table vs_3_handlers[] = {
2193 {BWRITERSIO_ADD, instr_handler},
2194 {BWRITERSIO_NOP, instr_handler},
2195 {BWRITERSIO_MOV, instr_handler},
2196 {BWRITERSIO_SUB, instr_handler},
2197 {BWRITERSIO_MAD, instr_handler},
2198 {BWRITERSIO_MUL, instr_handler},
2199 {BWRITERSIO_RCP, instr_handler},
2200 {BWRITERSIO_RSQ, instr_handler},
2201 {BWRITERSIO_DP3, instr_handler},
2202 {BWRITERSIO_DP4, instr_handler},
2203 {BWRITERSIO_MIN, instr_handler},
2204 {BWRITERSIO_MAX, instr_handler},
2205 {BWRITERSIO_SLT, instr_handler},
2206 {BWRITERSIO_SGE, instr_handler},
2207 {BWRITERSIO_ABS, instr_handler},
2208 {BWRITERSIO_EXP, instr_handler},
2209 {BWRITERSIO_LOG, instr_handler},
2210 {BWRITERSIO_EXPP, instr_handler},
2211 {BWRITERSIO_LOGP, instr_handler},
2212 {BWRITERSIO_DST, instr_handler},
2213 {BWRITERSIO_LRP, instr_handler},
2214 {BWRITERSIO_FRC, instr_handler},
2215 {BWRITERSIO_CRS, instr_handler},
2216 {BWRITERSIO_SGN, instr_handler},
2217 {BWRITERSIO_NRM, instr_handler},
2218 {BWRITERSIO_SINCOS, instr_handler},
2219 {BWRITERSIO_M4x4, instr_handler},
2220 {BWRITERSIO_M4x3, instr_handler},
2221 {BWRITERSIO_M3x4, instr_handler},
2222 {BWRITERSIO_M3x3, instr_handler},
2223 {BWRITERSIO_M3x2, instr_handler},
2224 {BWRITERSIO_LIT, instr_handler},
2225 {BWRITERSIO_POW, instr_handler},
2226 {BWRITERSIO_MOVA, instr_handler},
2228 {BWRITERSIO_CALL, instr_handler},
2229 {BWRITERSIO_CALLNZ, instr_handler},
2230 {BWRITERSIO_REP, instr_handler},
2231 {BWRITERSIO_ENDREP, instr_handler},
2232 {BWRITERSIO_IF, instr_handler},
2233 {BWRITERSIO_LABEL, instr_handler},
2234 {BWRITERSIO_IFC, instr_handler},
2235 {BWRITERSIO_ELSE, instr_handler},
2236 {BWRITERSIO_ENDIF, instr_handler},
2237 {BWRITERSIO_BREAK, instr_handler},
2238 {BWRITERSIO_BREAKC, instr_handler},
2239 {BWRITERSIO_LOOP, instr_handler},
2240 {BWRITERSIO_RET, instr_handler},
2241 {BWRITERSIO_ENDLOOP, instr_handler},
2243 {BWRITERSIO_SETP, instr_handler},
2244 {BWRITERSIO_BREAKP, instr_handler},
2245 {BWRITERSIO_TEXLDL, instr_handler},
2247 {BWRITERSIO_END, NULL},
2250 static const struct bytecode_backend vs_3_backend = {
2251 sm_3_header,
2252 end,
2253 sm_3_srcreg,
2254 sm_3_dstreg,
2255 sm_2_opcode,
2256 vs_3_handlers
2259 static const struct instr_handler_table ps_3_handlers[] = {
2260 {BWRITERSIO_ADD, instr_handler},
2261 {BWRITERSIO_NOP, instr_handler},
2262 {BWRITERSIO_MOV, instr_handler},
2263 {BWRITERSIO_SUB, instr_handler},
2264 {BWRITERSIO_MAD, instr_handler},
2265 {BWRITERSIO_MUL, instr_handler},
2266 {BWRITERSIO_RCP, instr_handler},
2267 {BWRITERSIO_RSQ, instr_handler},
2268 {BWRITERSIO_DP3, instr_handler},
2269 {BWRITERSIO_DP4, instr_handler},
2270 {BWRITERSIO_MIN, instr_handler},
2271 {BWRITERSIO_MAX, instr_handler},
2272 {BWRITERSIO_ABS, instr_handler},
2273 {BWRITERSIO_EXP, instr_handler},
2274 {BWRITERSIO_LOG, instr_handler},
2275 {BWRITERSIO_EXPP, instr_handler},
2276 {BWRITERSIO_LOGP, instr_handler},
2277 {BWRITERSIO_LRP, instr_handler},
2278 {BWRITERSIO_FRC, instr_handler},
2279 {BWRITERSIO_CRS, instr_handler},
2280 {BWRITERSIO_NRM, instr_handler},
2281 {BWRITERSIO_SINCOS, instr_handler},
2282 {BWRITERSIO_M4x4, instr_handler},
2283 {BWRITERSIO_M4x3, instr_handler},
2284 {BWRITERSIO_M3x4, instr_handler},
2285 {BWRITERSIO_M3x3, instr_handler},
2286 {BWRITERSIO_M3x2, instr_handler},
2287 {BWRITERSIO_POW, instr_handler},
2288 {BWRITERSIO_DP2ADD, instr_handler},
2289 {BWRITERSIO_CMP, instr_handler},
2291 {BWRITERSIO_CALL, instr_handler},
2292 {BWRITERSIO_CALLNZ, instr_handler},
2293 {BWRITERSIO_REP, instr_handler},
2294 {BWRITERSIO_ENDREP, instr_handler},
2295 {BWRITERSIO_IF, instr_handler},
2296 {BWRITERSIO_LABEL, instr_handler},
2297 {BWRITERSIO_IFC, instr_handler},
2298 {BWRITERSIO_ELSE, instr_handler},
2299 {BWRITERSIO_ENDIF, instr_handler},
2300 {BWRITERSIO_BREAK, instr_handler},
2301 {BWRITERSIO_BREAKC, instr_handler},
2302 {BWRITERSIO_LOOP, instr_handler},
2303 {BWRITERSIO_RET, instr_handler},
2304 {BWRITERSIO_ENDLOOP, instr_handler},
2306 {BWRITERSIO_SETP, instr_handler},
2307 {BWRITERSIO_BREAKP, instr_handler},
2308 {BWRITERSIO_TEXLDL, instr_handler},
2310 {BWRITERSIO_TEX, instr_handler},
2311 {BWRITERSIO_TEXLDP, instr_handler},
2312 {BWRITERSIO_TEXLDB, instr_handler},
2313 {BWRITERSIO_TEXKILL, instr_handler},
2314 {BWRITERSIO_DSX, instr_handler},
2315 {BWRITERSIO_DSY, instr_handler},
2316 {BWRITERSIO_TEXLDD, instr_handler},
2318 {BWRITERSIO_END, NULL},
2321 static const struct bytecode_backend ps_3_backend = {
2322 sm_3_header,
2323 end,
2324 sm_3_srcreg,
2325 sm_3_dstreg,
2326 sm_2_opcode,
2327 ps_3_handlers
2330 static const struct
2332 enum shader_type type;
2333 unsigned char major, minor;
2334 const struct bytecode_backend *backend;
2336 shader_backends[] =
2338 {ST_VERTEX, 1, 0, &vs_1_x_backend},
2339 {ST_VERTEX, 1, 1, &vs_1_x_backend},
2340 {ST_VERTEX, 2, 0, &vs_2_0_backend},
2341 {ST_VERTEX, 2, 1, &vs_2_x_backend},
2342 {ST_VERTEX, 3, 0, &vs_3_backend},
2344 {ST_PIXEL, 1, 0, &ps_1_0123_backend},
2345 {ST_PIXEL, 1, 1, &ps_1_0123_backend},
2346 {ST_PIXEL, 1, 2, &ps_1_0123_backend},
2347 {ST_PIXEL, 1, 3, &ps_1_0123_backend},
2348 {ST_PIXEL, 1, 4, &ps_1_4_backend},
2349 {ST_PIXEL, 2, 0, &ps_2_0_backend},
2350 {ST_PIXEL, 2, 1, &ps_2_x_backend},
2351 {ST_PIXEL, 3, 0, &ps_3_backend},
2354 static HRESULT call_instr_handler(struct bc_writer *writer,
2355 const struct instruction *instr,
2356 struct bytecode_buffer *buffer) {
2357 DWORD i=0;
2359 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
2360 if(instr->opcode == writer->funcs->instructions[i].opcode) {
2361 if(!writer->funcs->instructions[i].func) {
2362 WARN("Opcode %u not supported by this profile\n", instr->opcode);
2363 return E_INVALIDARG;
2365 writer->funcs->instructions[i].func(writer, instr, buffer);
2366 return S_OK;
2368 i++;
2371 FIXME("Unhandled instruction %u - %s\n", instr->opcode,
2372 debug_print_opcode(instr->opcode));
2373 return E_INVALIDARG;
2376 HRESULT shader_write_bytecode(const struct bwriter_shader *shader, DWORD **result, DWORD *size)
2378 struct bc_writer *writer;
2379 struct bytecode_buffer *buffer = NULL;
2380 HRESULT hr;
2381 unsigned int i;
2383 if(!shader){
2384 ERR("NULL shader structure, aborting\n");
2385 return E_FAIL;
2388 if (!(writer = d3dcompiler_alloc(sizeof(*writer))))
2389 return E_OUTOFMEMORY;
2391 for (i = 0; i < ARRAY_SIZE(shader_backends); ++i)
2393 if (shader->type == shader_backends[i].type
2394 && shader->major_version == shader_backends[i].major
2395 && shader->minor_version == shader_backends[i].minor)
2397 writer->funcs = shader_backends[i].backend;
2398 break;
2402 if (!writer->funcs)
2404 FIXME("Unsupported shader type %#x, version %u.%u.\n",
2405 shader->type, shader->major_version, shader->minor_version);
2406 d3dcompiler_free(writer);
2407 return E_NOTIMPL;
2410 writer->shader = shader;
2411 *result = NULL;
2413 buffer = allocate_buffer();
2414 if(!buffer) {
2415 WARN("Failed to allocate a buffer for the shader bytecode\n");
2416 hr = E_FAIL;
2417 goto error;
2420 /* Write shader type and version */
2421 put_dword(buffer, sm1_version(shader));
2423 writer->funcs->header(writer, shader, buffer);
2424 if(FAILED(writer->state)) {
2425 hr = writer->state;
2426 goto error;
2429 for(i = 0; i < shader->num_instrs; i++) {
2430 hr = call_instr_handler(writer, shader->instr[i], buffer);
2431 if(FAILED(hr)) {
2432 goto error;
2436 if(FAILED(writer->state)) {
2437 hr = writer->state;
2438 goto error;
2441 writer->funcs->end(writer, shader, buffer);
2443 if(FAILED(buffer->state)) {
2444 hr = buffer->state;
2445 goto error;
2448 *size = buffer->size * sizeof(DWORD);
2449 *result = buffer->data;
2450 buffer->data = NULL;
2451 hr = S_OK;
2453 error:
2454 if(buffer) {
2455 d3dcompiler_free(buffer->data);
2456 d3dcompiler_free(buffer);
2458 d3dcompiler_free(writer);
2459 return hr;
2462 void SlDeleteShader(struct bwriter_shader *shader) {
2463 unsigned int i, j;
2465 TRACE("Deleting shader %p\n", shader);
2467 for(i = 0; i < shader->num_cf; i++) {
2468 d3dcompiler_free(shader->constF[i]);
2470 d3dcompiler_free(shader->constF);
2471 for(i = 0; i < shader->num_ci; i++) {
2472 d3dcompiler_free(shader->constI[i]);
2474 d3dcompiler_free(shader->constI);
2475 for(i = 0; i < shader->num_cb; i++) {
2476 d3dcompiler_free(shader->constB[i]);
2478 d3dcompiler_free(shader->constB);
2480 d3dcompiler_free(shader->inputs);
2481 d3dcompiler_free(shader->outputs);
2482 d3dcompiler_free(shader->samplers);
2484 for(i = 0; i < shader->num_instrs; i++) {
2485 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
2486 d3dcompiler_free(shader->instr[i]->src[j].rel_reg);
2488 d3dcompiler_free(shader->instr[i]->src);
2489 d3dcompiler_free(shader->instr[i]->dst.rel_reg);
2490 d3dcompiler_free(shader->instr[i]);
2492 d3dcompiler_free(shader->instr);
2494 d3dcompiler_free(shader);