windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / d3dcompiler_43 / bytecodewriter.c
blobcd4aa4ba11e5fc709c618ceeced7da1c4264fb60
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, 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 = d3dcompiler_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 = d3dcompiler_alloc(sizeof(*shader->constF));
134 if (!shader->constF)
136 ERR("Failed to allocate the constants array\n");
137 return FALSE;
141 newconst = d3dcompiler_alloc(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 = d3dcompiler_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 = d3dcompiler_alloc(sizeof(*shader->constI));
176 if (!shader->constI)
178 ERR("Failed to allocate the constants array\n");
179 return FALSE;
183 newconst = d3dcompiler_alloc(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 = d3dcompiler_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 = d3dcompiler_alloc(sizeof(*shader->constB));
218 if (!shader->constB)
220 ERR("Failed to allocate the constants array\n");
221 return FALSE;
225 newconst = d3dcompiler_alloc(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 = d3dcompiler_alloc(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 = d3dcompiler_realloc(*decl,
280 sizeof(**decl) * ((*num) + 1));
281 if (!newdecl)
283 ERR("Error reallocating declarations array\n");
284 return FALSE;
286 *decl = newdecl;
288 (*decl)[*num].usage = usage;
289 (*decl)[*num].usage_idx = usage_idx;
290 (*decl)[*num].regnum = regnum;
291 (*decl)[*num].mod = mod;
292 (*decl)[*num].writemask = writemask;
293 (*decl)[*num].builtin = builtin;
294 (*num)++;
296 return TRUE;
299 BOOL record_sampler(struct bwriter_shader *shader, uint32_t samptype, uint32_t mod, uint32_t regnum) {
300 unsigned int i;
302 if (!shader)
303 return FALSE;
305 if (shader->num_samplers == 0)
307 shader->samplers = d3dcompiler_alloc(sizeof(*shader->samplers));
308 if (!shader->samplers)
310 ERR("Error allocating samplers array\n");
311 return FALSE;
314 else
316 struct samplerdecl *newarray;
318 for (i = 0; i < shader->num_samplers; i++)
320 if (shader->samplers[i].regnum == regnum)
322 WARN("Sampler %u already declared\n", regnum);
323 /* This is not an error as far as the assembler is concerned.
324 * Direct3D might refuse to load the compiled shader though */
328 newarray = d3dcompiler_realloc(shader->samplers, sizeof(*shader->samplers) * (shader->num_samplers + 1));
329 if (!newarray)
331 ERR("Error reallocating samplers array\n");
332 return FALSE;
334 shader->samplers = newarray;
337 shader->samplers[shader->num_samplers].type = samptype;
338 shader->samplers[shader->num_samplers].mod = mod;
339 shader->samplers[shader->num_samplers].regnum = regnum;
340 shader->num_samplers++;
341 return TRUE;
344 struct bytecode_buffer
346 uint32_t *data;
347 unsigned int size, alloc_size;
348 HRESULT state;
351 struct bc_writer;
353 typedef void (*instr_writer)(struct bc_writer *writer, const struct instruction *instr,
354 struct bytecode_buffer *buffer);
356 struct bytecode_backend
358 void (*header)(struct bc_writer *writer, const struct bwriter_shader *shader,
359 struct bytecode_buffer *buffer);
360 void (*end)(struct bc_writer *writer, const struct bwriter_shader *shader,
361 struct bytecode_buffer *buffer);
362 void (*srcreg)(struct bc_writer *writer, const struct shader_reg *reg,
363 struct bytecode_buffer *buffer);
364 void (*dstreg)(struct bc_writer *writer, const struct shader_reg *reg,
365 struct bytecode_buffer *buffer, uint32_t shift, uint32_t mod);
366 void (*opcode)(struct bc_writer *writer, const struct instruction *instr,
367 uint32_t token, struct bytecode_buffer *buffer);
369 const struct instr_handler_table
371 uint32_t opcode;
372 instr_writer func;
373 } *instructions;
376 struct bc_writer
378 const struct bytecode_backend *funcs;
379 const struct bwriter_shader *shader;
381 HRESULT state;
383 /* Vertex shader varying mapping. */
384 uint32_t oPos_regnum, oD_regnum[2], oT_regnum[8], oFog_regnum, oFog_mask, oPts_regnum, oPts_mask;
386 /* Pixel shader varying mapping. */
387 uint32_t t_regnum[8], v_regnum[2];
391 /* shader bytecode buffer manipulation functions.
392 * allocate_buffer creates a new buffer structure, put_u32 adds a new
393 * uint32_t to the buffer. In the rare case of a memory allocation failure
394 * when trying to grow the buffer a flag is set in the buffer to mark it
395 * invalid. This avoids return value checking and passing in many places
397 static struct bytecode_buffer *allocate_buffer(void) {
398 struct bytecode_buffer *ret;
400 ret = d3dcompiler_alloc(sizeof(*ret));
401 if(!ret) return NULL;
402 ret->state = S_OK;
403 return ret;
406 static void put_u32(struct bytecode_buffer *buffer, uint32_t value)
408 if (FAILED(buffer->state))
409 return;
411 if (!array_reserve((void **)&buffer->data, &buffer->alloc_size, buffer->size + 1, sizeof(*buffer->data)))
413 buffer->state = E_OUTOFMEMORY;
414 return;
417 buffer->data[buffer->size++] = value;
420 /* bwriter -> d3d9 conversion functions. */
422 static uint32_t sm1_version(const struct bwriter_shader *shader)
424 switch (shader->type)
426 case ST_VERTEX:
427 return D3DVS_VERSION(shader->major_version, shader->minor_version);
428 case ST_PIXEL:
429 return D3DPS_VERSION(shader->major_version, shader->minor_version);
430 default:
431 ERR("Invalid shader type %#x.\n", shader->type);
432 return 0;
436 static uint32_t d3d9_swizzle(uint32_t bwriter_swizzle)
438 uint32_t ret = 0;
440 if ((bwriter_swizzle & BWRITERVS_X_X) == BWRITERVS_X_X) ret |= D3DVS_X_X;
441 if ((bwriter_swizzle & BWRITERVS_X_Y) == BWRITERVS_X_Y) ret |= D3DVS_X_Y;
442 if ((bwriter_swizzle & BWRITERVS_X_Z) == BWRITERVS_X_Z) ret |= D3DVS_X_Z;
443 if ((bwriter_swizzle & BWRITERVS_X_W) == BWRITERVS_X_W) ret |= D3DVS_X_W;
445 if ((bwriter_swizzle & BWRITERVS_Y_X) == BWRITERVS_Y_X) ret |= D3DVS_Y_X;
446 if ((bwriter_swizzle & BWRITERVS_Y_Y) == BWRITERVS_Y_Y) ret |= D3DVS_Y_Y;
447 if ((bwriter_swizzle & BWRITERVS_Y_Z) == BWRITERVS_Y_Z) ret |= D3DVS_Y_Z;
448 if ((bwriter_swizzle & BWRITERVS_Y_W) == BWRITERVS_Y_W) ret |= D3DVS_Y_W;
450 if ((bwriter_swizzle & BWRITERVS_Z_X) == BWRITERVS_Z_X) ret |= D3DVS_Z_X;
451 if ((bwriter_swizzle & BWRITERVS_Z_Y) == BWRITERVS_Z_Y) ret |= D3DVS_Z_Y;
452 if ((bwriter_swizzle & BWRITERVS_Z_Z) == BWRITERVS_Z_Z) ret |= D3DVS_Z_Z;
453 if ((bwriter_swizzle & BWRITERVS_Z_W) == BWRITERVS_Z_W) ret |= D3DVS_Z_W;
455 if ((bwriter_swizzle & BWRITERVS_W_X) == BWRITERVS_W_X) ret |= D3DVS_W_X;
456 if ((bwriter_swizzle & BWRITERVS_W_Y) == BWRITERVS_W_Y) ret |= D3DVS_W_Y;
457 if ((bwriter_swizzle & BWRITERVS_W_Z) == BWRITERVS_W_Z) ret |= D3DVS_W_Z;
458 if ((bwriter_swizzle & BWRITERVS_W_W) == BWRITERVS_W_W) ret |= D3DVS_W_W;
460 return ret;
463 static uint32_t d3d9_writemask(uint32_t bwriter_writemask)
465 uint32_t ret = 0;
467 if (bwriter_writemask & BWRITERSP_WRITEMASK_0) ret |= D3DSP_WRITEMASK_0;
468 if (bwriter_writemask & BWRITERSP_WRITEMASK_1) ret |= D3DSP_WRITEMASK_1;
469 if (bwriter_writemask & BWRITERSP_WRITEMASK_2) ret |= D3DSP_WRITEMASK_2;
470 if (bwriter_writemask & BWRITERSP_WRITEMASK_3) ret |= D3DSP_WRITEMASK_3;
472 return ret;
475 static uint32_t d3d9_srcmod(uint32_t bwriter_srcmod)
477 switch (bwriter_srcmod)
479 case BWRITERSPSM_NONE: return D3DSPSM_NONE;
480 case BWRITERSPSM_NEG: return D3DSPSM_NEG;
481 case BWRITERSPSM_BIAS: return D3DSPSM_BIAS;
482 case BWRITERSPSM_BIASNEG: return D3DSPSM_BIASNEG;
483 case BWRITERSPSM_SIGN: return D3DSPSM_SIGN;
484 case BWRITERSPSM_SIGNNEG: return D3DSPSM_SIGNNEG;
485 case BWRITERSPSM_COMP: return D3DSPSM_COMP;
486 case BWRITERSPSM_X2: return D3DSPSM_X2;
487 case BWRITERSPSM_X2NEG: return D3DSPSM_X2NEG;
488 case BWRITERSPSM_DZ: return D3DSPSM_DZ;
489 case BWRITERSPSM_DW: return D3DSPSM_DW;
490 case BWRITERSPSM_ABS: return D3DSPSM_ABS;
491 case BWRITERSPSM_ABSNEG: return D3DSPSM_ABSNEG;
492 case BWRITERSPSM_NOT: return D3DSPSM_NOT;
493 default:
494 FIXME("Unhandled BWRITERSPSM token %#x.\n", bwriter_srcmod);
495 return 0;
499 static uint32_t d3d9_dstmod(uint32_t bwriter_mod)
501 uint32_t ret = 0;
503 if (bwriter_mod & BWRITERSPDM_SATURATE) ret |= D3DSPDM_SATURATE;
504 if (bwriter_mod & BWRITERSPDM_PARTIALPRECISION) ret |= D3DSPDM_PARTIALPRECISION;
505 if (bwriter_mod & BWRITERSPDM_MSAMPCENTROID) ret |= D3DSPDM_MSAMPCENTROID;
507 return ret;
510 static uint32_t d3d9_comparetype(uint32_t asmshader_comparetype)
512 switch (asmshader_comparetype)
514 case BWRITER_COMPARISON_GT: return D3DSPC_GT;
515 case BWRITER_COMPARISON_EQ: return D3DSPC_EQ;
516 case BWRITER_COMPARISON_GE: return D3DSPC_GE;
517 case BWRITER_COMPARISON_LT: return D3DSPC_LT;
518 case BWRITER_COMPARISON_NE: return D3DSPC_NE;
519 case BWRITER_COMPARISON_LE: return D3DSPC_LE;
520 default:
521 FIXME("Unexpected BWRITER_COMPARISON type %#x.\n", asmshader_comparetype);
522 return 0;
526 static uint32_t d3d9_sampler(uint32_t bwriter_sampler)
528 if (bwriter_sampler == BWRITERSTT_UNKNOWN) return D3DSTT_UNKNOWN;
529 if (bwriter_sampler == BWRITERSTT_1D) return D3DSTT_1D;
530 if (bwriter_sampler == BWRITERSTT_2D) return D3DSTT_2D;
531 if (bwriter_sampler == BWRITERSTT_CUBE) return D3DSTT_CUBE;
532 if (bwriter_sampler == BWRITERSTT_VOLUME) return D3DSTT_VOLUME;
533 FIXME("Unexpected BWRITERSAMPLER_TEXTURE_TYPE type %#x.\n", bwriter_sampler);
535 return 0;
538 static uint32_t d3d9_register(uint32_t bwriter_register)
540 if (bwriter_register == BWRITERSPR_TEMP) return D3DSPR_TEMP;
541 if (bwriter_register == BWRITERSPR_INPUT) return D3DSPR_INPUT;
542 if (bwriter_register == BWRITERSPR_CONST) return D3DSPR_CONST;
543 if (bwriter_register == BWRITERSPR_ADDR) return D3DSPR_ADDR;
544 if (bwriter_register == BWRITERSPR_TEXTURE) return D3DSPR_TEXTURE;
545 if (bwriter_register == BWRITERSPR_RASTOUT) return D3DSPR_RASTOUT;
546 if (bwriter_register == BWRITERSPR_ATTROUT) return D3DSPR_ATTROUT;
547 if (bwriter_register == BWRITERSPR_TEXCRDOUT) return D3DSPR_TEXCRDOUT;
548 if (bwriter_register == BWRITERSPR_OUTPUT) return D3DSPR_OUTPUT;
549 if (bwriter_register == BWRITERSPR_CONSTINT) return D3DSPR_CONSTINT;
550 if (bwriter_register == BWRITERSPR_COLOROUT) return D3DSPR_COLOROUT;
551 if (bwriter_register == BWRITERSPR_DEPTHOUT) return D3DSPR_DEPTHOUT;
552 if (bwriter_register == BWRITERSPR_SAMPLER) return D3DSPR_SAMPLER;
553 if (bwriter_register == BWRITERSPR_CONSTBOOL) return D3DSPR_CONSTBOOL;
554 if (bwriter_register == BWRITERSPR_LOOP) return D3DSPR_LOOP;
555 if (bwriter_register == BWRITERSPR_MISCTYPE) return D3DSPR_MISCTYPE;
556 if (bwriter_register == BWRITERSPR_LABEL) return D3DSPR_LABEL;
557 if (bwriter_register == BWRITERSPR_PREDICATE) return D3DSPR_PREDICATE;
559 FIXME("Unexpected BWRITERSPR %#x.\n", bwriter_register);
560 return ~0U;
563 static uint32_t d3d9_opcode(uint32_t bwriter_opcode)
565 switch (bwriter_opcode)
567 case BWRITERSIO_NOP: return D3DSIO_NOP;
568 case BWRITERSIO_MOV: return D3DSIO_MOV;
569 case BWRITERSIO_ADD: return D3DSIO_ADD;
570 case BWRITERSIO_SUB: return D3DSIO_SUB;
571 case BWRITERSIO_MAD: return D3DSIO_MAD;
572 case BWRITERSIO_MUL: return D3DSIO_MUL;
573 case BWRITERSIO_RCP: return D3DSIO_RCP;
574 case BWRITERSIO_RSQ: return D3DSIO_RSQ;
575 case BWRITERSIO_DP3: return D3DSIO_DP3;
576 case BWRITERSIO_DP4: return D3DSIO_DP4;
577 case BWRITERSIO_MIN: return D3DSIO_MIN;
578 case BWRITERSIO_MAX: return D3DSIO_MAX;
579 case BWRITERSIO_SLT: return D3DSIO_SLT;
580 case BWRITERSIO_SGE: return D3DSIO_SGE;
581 case BWRITERSIO_EXP: return D3DSIO_EXP;
582 case BWRITERSIO_LOG: return D3DSIO_LOG;
583 case BWRITERSIO_LIT: return D3DSIO_LIT;
584 case BWRITERSIO_DST: return D3DSIO_DST;
585 case BWRITERSIO_LRP: return D3DSIO_LRP;
586 case BWRITERSIO_FRC: return D3DSIO_FRC;
587 case BWRITERSIO_M4x4: return D3DSIO_M4x4;
588 case BWRITERSIO_M4x3: return D3DSIO_M4x3;
589 case BWRITERSIO_M3x4: return D3DSIO_M3x4;
590 case BWRITERSIO_M3x3: return D3DSIO_M3x3;
591 case BWRITERSIO_M3x2: return D3DSIO_M3x2;
592 case BWRITERSIO_CALL: return D3DSIO_CALL;
593 case BWRITERSIO_CALLNZ: return D3DSIO_CALLNZ;
594 case BWRITERSIO_LOOP: return D3DSIO_LOOP;
595 case BWRITERSIO_RET: return D3DSIO_RET;
596 case BWRITERSIO_ENDLOOP: return D3DSIO_ENDLOOP;
597 case BWRITERSIO_LABEL: return D3DSIO_LABEL;
598 case BWRITERSIO_DCL: return D3DSIO_DCL;
599 case BWRITERSIO_POW: return D3DSIO_POW;
600 case BWRITERSIO_CRS: return D3DSIO_CRS;
601 case BWRITERSIO_SGN: return D3DSIO_SGN;
602 case BWRITERSIO_ABS: return D3DSIO_ABS;
603 case BWRITERSIO_NRM: return D3DSIO_NRM;
604 case BWRITERSIO_SINCOS: return D3DSIO_SINCOS;
605 case BWRITERSIO_REP: return D3DSIO_REP;
606 case BWRITERSIO_ENDREP: return D3DSIO_ENDREP;
607 case BWRITERSIO_IF: return D3DSIO_IF;
608 case BWRITERSIO_IFC: return D3DSIO_IFC;
609 case BWRITERSIO_ELSE: return D3DSIO_ELSE;
610 case BWRITERSIO_ENDIF: return D3DSIO_ENDIF;
611 case BWRITERSIO_BREAK: return D3DSIO_BREAK;
612 case BWRITERSIO_BREAKC: return D3DSIO_BREAKC;
613 case BWRITERSIO_MOVA: return D3DSIO_MOVA;
614 case BWRITERSIO_DEFB: return D3DSIO_DEFB;
615 case BWRITERSIO_DEFI: return D3DSIO_DEFI;
617 case BWRITERSIO_TEXCOORD: return D3DSIO_TEXCOORD;
618 case BWRITERSIO_TEXKILL: return D3DSIO_TEXKILL;
619 case BWRITERSIO_TEX: return D3DSIO_TEX;
620 case BWRITERSIO_TEXBEM: return D3DSIO_TEXBEM;
621 case BWRITERSIO_TEXBEML: return D3DSIO_TEXBEML;
622 case BWRITERSIO_TEXREG2AR: return D3DSIO_TEXREG2AR;
623 case BWRITERSIO_TEXREG2GB: return D3DSIO_TEXREG2GB;
624 case BWRITERSIO_TEXM3x2PAD: return D3DSIO_TEXM3x2PAD;
625 case BWRITERSIO_TEXM3x2TEX: return D3DSIO_TEXM3x2TEX;
626 case BWRITERSIO_TEXM3x3PAD: return D3DSIO_TEXM3x3PAD;
627 case BWRITERSIO_TEXM3x3TEX: return D3DSIO_TEXM3x3TEX;
628 case BWRITERSIO_TEXM3x3SPEC: return D3DSIO_TEXM3x3SPEC;
629 case BWRITERSIO_TEXM3x3VSPEC:return D3DSIO_TEXM3x3VSPEC;
630 case BWRITERSIO_EXPP: return D3DSIO_EXPP;
631 case BWRITERSIO_LOGP: return D3DSIO_LOGP;
632 case BWRITERSIO_CND: return D3DSIO_CND;
633 case BWRITERSIO_DEF: return D3DSIO_DEF;
634 case BWRITERSIO_TEXREG2RGB: return D3DSIO_TEXREG2RGB;
635 case BWRITERSIO_TEXDP3TEX: return D3DSIO_TEXDP3TEX;
636 case BWRITERSIO_TEXM3x2DEPTH:return D3DSIO_TEXM3x2DEPTH;
637 case BWRITERSIO_TEXDP3: return D3DSIO_TEXDP3;
638 case BWRITERSIO_TEXM3x3: return D3DSIO_TEXM3x3;
639 case BWRITERSIO_TEXDEPTH: return D3DSIO_TEXDEPTH;
640 case BWRITERSIO_CMP: return D3DSIO_CMP;
641 case BWRITERSIO_BEM: return D3DSIO_BEM;
642 case BWRITERSIO_DP2ADD: return D3DSIO_DP2ADD;
643 case BWRITERSIO_DSX: return D3DSIO_DSX;
644 case BWRITERSIO_DSY: return D3DSIO_DSY;
645 case BWRITERSIO_TEXLDD: return D3DSIO_TEXLDD;
646 case BWRITERSIO_SETP: return D3DSIO_SETP;
647 case BWRITERSIO_TEXLDL: return D3DSIO_TEXLDL;
648 case BWRITERSIO_BREAKP: return D3DSIO_BREAKP;
650 case BWRITERSIO_PHASE: return D3DSIO_PHASE;
651 case BWRITERSIO_COMMENT: return D3DSIO_COMMENT;
652 case BWRITERSIO_END: return D3DSIO_END;
654 case BWRITERSIO_TEXLDP: return D3DSIO_TEX | D3DSI_TEXLD_PROJECT;
655 case BWRITERSIO_TEXLDB: return D3DSIO_TEX | D3DSI_TEXLD_BIAS;
657 default:
658 FIXME("Unhandled BWRITERSIO token %#x.\n", bwriter_opcode);
659 return ~0U;
663 static uint32_t d3dsp_register(D3DSHADER_PARAM_REGISTER_TYPE type, uint32_t num)
665 return ((type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
666 ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
667 (num & D3DSP_REGNUM_MASK); /* No shift */
670 /******************************************************
671 * Implementation of the writer functions starts here *
672 ******************************************************/
673 static void write_declarations(struct bc_writer *writer, struct bytecode_buffer *buffer,
674 const struct declaration *decls, unsigned int num, uint32_t type)
676 uint32_t instr_dcl = D3DSIO_DCL;
677 uint32_t token;
678 unsigned int i;
679 struct shader_reg reg;
681 ZeroMemory(&reg, sizeof(reg));
683 if (writer->shader->major_version > 1)
684 instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT;
686 for(i = 0; i < num; i++) {
687 if(decls[i].builtin) continue;
689 /* Write the DCL instruction */
690 put_u32(buffer, instr_dcl);
692 /* Write the usage and index */
693 token = (1u << 31); /* Bit 31 of non-instruction opcodes is 1 */
694 token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK;
695 token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK;
696 put_u32(buffer, token);
698 /* Write the dest register */
699 reg.type = type;
700 reg.regnum = decls[i].regnum;
701 reg.writemask = decls[i].writemask;
702 writer->funcs->dstreg(writer, &reg, buffer, 0, decls[i].mod);
706 static void write_const(struct constant **consts, int num, uint32_t opcode, uint32_t reg_type, struct bytecode_buffer *buffer, BOOL len)
708 const uint32_t reg = (1u << 31) | d3dsp_register( reg_type, 0 ) | D3DSP_WRITEMASK_ALL;
709 uint32_t instr_def = opcode;
710 unsigned int i;
712 if(len) {
713 if(opcode == D3DSIO_DEFB)
714 instr_def |= 2 << D3DSI_INSTLENGTH_SHIFT;
715 else
716 instr_def |= 5 << D3DSI_INSTLENGTH_SHIFT;
719 for(i = 0; i < num; i++) {
720 /* Write the DEF instruction */
721 put_u32(buffer, instr_def);
723 put_u32(buffer, reg | (consts[i]->regnum & D3DSP_REGNUM_MASK));
724 put_u32(buffer, consts[i]->value[0].d);
725 if(opcode != D3DSIO_DEFB) {
726 put_u32(buffer, consts[i]->value[1].d);
727 put_u32(buffer, consts[i]->value[2].d);
728 put_u32(buffer, consts[i]->value[3].d);
733 static void write_constF(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
734 write_const(shader->constF, shader->num_cf, D3DSIO_DEF, D3DSPR_CONST, buffer, len);
737 /* This function looks for VS 1/2 registers mapping to VS 3 output registers */
738 static HRESULT vs_find_builtin_varyings(struct bc_writer *writer, const struct bwriter_shader *shader)
740 uint32_t usage, usage_idx, writemask, regnum;
741 unsigned int i;
743 for (i = 0; i < shader->num_outputs; i++)
745 if (!shader->outputs[i].builtin)
746 continue;
748 usage = shader->outputs[i].usage;
749 usage_idx = shader->outputs[i].usage_idx;
750 writemask = shader->outputs[i].writemask;
751 regnum = shader->outputs[i].regnum;
753 switch (usage)
755 case BWRITERDECLUSAGE_POSITION:
756 case BWRITERDECLUSAGE_POSITIONT:
757 if (usage_idx > 0)
759 WARN("dcl_position%u not supported in sm 1/2 shaders.\n", usage_idx);
760 return E_INVALIDARG;
762 TRACE("o%u is oPos.\n", regnum);
763 writer->oPos_regnum = regnum;
764 break;
766 case BWRITERDECLUSAGE_COLOR:
767 if (usage_idx > 1)
769 WARN("dcl_color%u not supported in sm 1/2 shaders.\n", usage_idx);
770 return E_INVALIDARG;
772 if (writemask != BWRITERSP_WRITEMASK_ALL)
774 WARN("Only WRITEMASK_ALL is supported on color in sm 1/2\n");
775 return E_INVALIDARG;
777 TRACE("o%u is oD%u.\n", regnum, usage_idx);
778 writer->oD_regnum[usage_idx] = regnum;
779 break;
781 case BWRITERDECLUSAGE_TEXCOORD:
782 if (usage_idx >= 8)
784 WARN("dcl_color%u not supported in sm 1/2 shaders.\n", usage_idx);
785 return E_INVALIDARG;
787 if (writemask != (BWRITERSP_WRITEMASK_0)
788 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1)
789 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2)
790 && writemask != (BWRITERSP_WRITEMASK_ALL))
792 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
793 return E_INVALIDARG;
795 TRACE("o%u is oT%u.\n", regnum, usage_idx);
796 writer->oT_regnum[usage_idx] = regnum;
797 break;
799 case BWRITERDECLUSAGE_PSIZE:
800 if (usage_idx > 0)
802 WARN("dcl_psize%u not supported in sm 1/2 shaders.\n", usage_idx);
803 return E_INVALIDARG;
805 TRACE("o%u writemask 0x%08x is oPts.\n", regnum, writemask);
806 writer->oPts_regnum = regnum;
807 writer->oPts_mask = writemask;
808 break;
810 case BWRITERDECLUSAGE_FOG:
811 if (usage_idx > 0)
813 WARN("dcl_fog%u not supported in sm 1 shaders.\n", usage_idx);
814 return E_INVALIDARG;
816 if (writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1
817 && writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3)
819 WARN("Unsupported fog writemask\n");
820 return E_INVALIDARG;
822 TRACE("o%u writemask 0x%08x is oFog.\n", regnum, writemask);
823 writer->oFog_regnum = regnum;
824 writer->oFog_mask = writemask;
825 break;
827 default:
828 WARN("Varying type %u is not supported in shader model 1.x.\n", usage);
829 return E_INVALIDARG;
833 return S_OK;
836 static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
837 HRESULT hr;
839 if(shader->num_ci || shader->num_cb) {
840 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
841 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
842 This->state = E_INVALIDARG;
843 return;
846 hr = vs_find_builtin_varyings(This, shader);
847 if(FAILED(hr)) {
848 This->state = hr;
849 return;
852 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
853 write_constF(shader, buffer, FALSE);
856 static HRESULT find_ps_builtin_semantics(struct bc_writer *writer, const struct bwriter_shader *shader,
857 uint32_t texcoords)
859 uint32_t usage, usage_idx, writemask, regnum;
860 unsigned int i;
862 writer->v_regnum[0] = -1;
863 writer->v_regnum[1] = -1;
864 for (i = 0; i < 8; i++)
865 writer->t_regnum[i] = -1;
867 for (i = 0; i < shader->num_inputs; i++)
869 if (!shader->inputs[i].builtin)
870 continue;
872 usage = shader->inputs[i].usage;
873 usage_idx = shader->inputs[i].usage_idx;
874 writemask = shader->inputs[i].writemask;
875 regnum = shader->inputs[i].regnum;
877 switch (usage)
879 case BWRITERDECLUSAGE_COLOR:
880 if (usage_idx > 1)
882 WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
883 return E_INVALIDARG;
885 if (writemask != BWRITERSP_WRITEMASK_ALL)
887 WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
888 return E_INVALIDARG;
890 TRACE("v%u is v%u\n", regnum, usage_idx);
891 writer->v_regnum[usage_idx] = regnum;
892 break;
894 case BWRITERDECLUSAGE_TEXCOORD:
895 if (usage_idx > texcoords)
897 WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
898 return E_INVALIDARG;
900 if (writemask != (BWRITERSP_WRITEMASK_0)
901 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1)
902 && writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2)
903 && writemask != (BWRITERSP_WRITEMASK_ALL))
904 WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
905 else
906 writemask = BWRITERSP_WRITEMASK_ALL;
907 TRACE("v%u is t%u\n", regnum, usage_idx);
908 writer->t_regnum[usage_idx] = regnum;
909 break;
911 default:
912 WARN("Varying type %u is not supported in shader model 1.x\n", usage);
913 return E_INVALIDARG;
917 return S_OK;
920 static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
921 HRESULT hr;
923 /* First check the constants and varyings, and complain if unsupported things are used */
924 if(shader->num_ci || shader->num_cb) {
925 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
926 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
927 This->state = E_INVALIDARG;
928 return;
931 hr = find_ps_builtin_semantics(This, shader, 4);
932 if(FAILED(hr)) {
933 This->state = hr;
934 return;
937 write_constF(shader, buffer, FALSE);
940 static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
941 HRESULT hr;
943 /* First check the constants and varyings, and complain if unsupported things are used */
944 if(shader->num_ci || shader->num_cb) {
945 WARN("Int and bool constants are not supported in shader model 1 shaders\n");
946 WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
947 This->state = E_INVALIDARG;
948 return;
950 hr = find_ps_builtin_semantics(This, shader, 6);
951 if(FAILED(hr)) {
952 This->state = hr;
953 return;
956 write_constF(shader, buffer, FALSE);
959 static void end(struct bc_writer *writer, const struct bwriter_shader *shader, struct bytecode_buffer *buffer)
961 put_u32(buffer, D3DSIO_END);
964 static uint32_t map_vs_output(struct bc_writer *writer, uint32_t regnum, uint32_t mask, BOOL *has_components)
966 unsigned int i;
968 *has_components = TRUE;
969 if (regnum == writer->oPos_regnum)
971 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POSITION );
973 if (regnum == writer->oFog_regnum && mask == writer->oFog_mask)
975 *has_components = FALSE;
976 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_FOG ) | D3DSP_WRITEMASK_ALL;
978 if (regnum == writer->oPts_regnum && mask == writer->oPts_mask)
980 *has_components = FALSE;
981 return d3dsp_register( D3DSPR_RASTOUT, D3DSRO_POINT_SIZE ) | D3DSP_WRITEMASK_ALL;
983 for (i = 0; i < 2; i++)
985 if (regnum == writer->oD_regnum[i])
986 return d3dsp_register( D3DSPR_ATTROUT, i );
988 for (i = 0; i < 8; i++)
990 if (regnum == writer->oT_regnum[i])
991 return d3dsp_register( D3DSPR_TEXCRDOUT, i );
994 /* The varying must be undeclared - if an unsupported varying was declared,
995 * the vs_find_builtin_varyings function would have caught it and this code
996 * would not run */
997 WARN("Undeclared varying %u.\n", regnum);
998 writer->state = E_INVALIDARG;
999 return -1;
1002 static void vs_12_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1003 uint32_t shift, uint32_t mod)
1005 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1006 BOOL has_wmask;
1008 if (reg->rel_reg)
1010 WARN("Relative addressing not supported for destination registers\n");
1011 writer->state = E_INVALIDARG;
1012 return;
1015 switch (reg->type)
1017 case BWRITERSPR_OUTPUT:
1018 token |= map_vs_output(writer, reg->regnum, reg->writemask, &has_wmask);
1019 break;
1021 case BWRITERSPR_RASTOUT:
1022 case BWRITERSPR_ATTROUT:
1023 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1024 * but are unexpected. If we hit this path it might be due to an error.
1026 FIXME("Unexpected register type %u.\n", reg->type);
1027 /* drop through */
1028 case BWRITERSPR_INPUT:
1029 case BWRITERSPR_TEMP:
1030 case BWRITERSPR_CONST:
1031 token |= d3dsp_register( reg->type, reg->regnum );
1032 has_wmask = TRUE;
1033 break;
1035 case BWRITERSPR_ADDR:
1036 if (reg->regnum != 0)
1038 WARN("Only a0 exists\n");
1039 writer->state = E_INVALIDARG;
1040 return;
1042 token |= d3dsp_register( D3DSPR_ADDR, 0 );
1043 has_wmask = TRUE;
1044 break;
1046 case BWRITERSPR_PREDICATE:
1047 if (writer->shader->major_version != 2 || writer->shader->minor_version != 1)
1049 WARN("Predicate register is allowed only in vs_2_x\n");
1050 writer->state = E_INVALIDARG;
1051 return;
1053 if (reg->regnum != 0)
1055 WARN("Only predicate register p0 exists\n");
1056 writer->state = E_INVALIDARG;
1057 return;
1059 token |= d3dsp_register( D3DSPR_PREDICATE, 0 );
1060 has_wmask = TRUE;
1061 break;
1063 default:
1064 WARN("Invalid register type for 1.x-2.x vertex shader\n");
1065 writer->state = E_INVALIDARG;
1066 return;
1069 /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
1070 * into the bytecode and since the compiler doesn't do such checks write them
1071 * (the checks are done by the undocumented shader validator)
1073 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1074 token |= d3d9_dstmod(mod);
1076 if (has_wmask)
1077 token |= d3d9_writemask(reg->writemask);
1078 put_u32(buffer, token);
1081 static void vs_1_x_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1083 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1084 uint32_t component;
1085 BOOL has_swizzle;
1087 switch (reg->type)
1089 case BWRITERSPR_OUTPUT:
1090 /* Map the swizzle to a writemask, the format expected by
1091 * map_vs_output */
1092 switch (reg->swizzle)
1094 case BWRITERVS_SWIZZLE_X:
1095 component = BWRITERSP_WRITEMASK_0;
1096 break;
1097 case BWRITERVS_SWIZZLE_Y:
1098 component = BWRITERSP_WRITEMASK_1;
1099 break;
1100 case BWRITERVS_SWIZZLE_Z:
1101 component = BWRITERSP_WRITEMASK_2;
1102 break;
1103 case BWRITERVS_SWIZZLE_W:
1104 component = BWRITERSP_WRITEMASK_3;
1105 break;
1106 default:
1107 component = 0;
1109 token |= map_vs_output(writer, reg->regnum, component, &has_swizzle);
1110 break;
1112 case BWRITERSPR_RASTOUT:
1113 case BWRITERSPR_ATTROUT:
1114 /* These registers are mapped to input and output regs. They can
1115 * be encoded in the bytecode, but are unexpected. If we hit this
1116 * path it might be due to an error. */
1117 FIXME("Unexpected register type %u.\n", reg->type);
1118 /* drop through */
1119 case BWRITERSPR_INPUT:
1120 case BWRITERSPR_TEMP:
1121 case BWRITERSPR_CONST:
1122 case BWRITERSPR_ADDR:
1123 token |= d3dsp_register(reg->type, reg->regnum);
1124 if (reg->rel_reg)
1126 if (reg->rel_reg->type != BWRITERSPR_ADDR || reg->rel_reg->regnum != 0
1127 || reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X)
1129 WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
1130 writer->state = E_INVALIDARG;
1131 return;
1133 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1135 break;
1137 default:
1138 WARN("Invalid register type for 1.x vshader\n");
1139 writer->state = E_INVALIDARG;
1140 return;
1143 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1145 token |= d3d9_srcmod(reg->srcmod);
1146 put_u32(buffer, token);
1149 static void write_srcregs(struct bc_writer *writer, const struct instruction *instr, struct bytecode_buffer *buffer)
1151 unsigned int i;
1153 if (instr->has_predicate)
1154 writer->funcs->srcreg(writer, &instr->predicate, buffer);
1156 for (i = 0; i < instr->num_srcs; ++i)
1157 writer->funcs->srcreg(writer, &instr->src[i], buffer);
1160 static uint32_t map_ps13_temp(struct bc_writer *writer, const struct shader_reg *reg)
1162 if (reg->regnum == T0_REG)
1163 return d3dsp_register(D3DSPR_TEXTURE, 0);
1164 if (reg->regnum == T1_REG)
1165 return d3dsp_register(D3DSPR_TEXTURE, 1);
1166 if(reg->regnum == T2_REG)
1167 return d3dsp_register(D3DSPR_TEXTURE, 2);
1168 if (reg->regnum == T3_REG)
1169 return d3dsp_register(D3DSPR_TEXTURE, 3);
1170 return d3dsp_register(D3DSPR_TEMP, reg->regnum);
1173 static uint32_t map_ps_input(struct bc_writer *writer, const struct shader_reg *reg)
1175 unsigned int i;
1177 /* Map color interpolators */
1178 for (i = 0; i < ARRAY_SIZE(writer->v_regnum); ++i)
1180 if (reg->regnum == writer->v_regnum[i])
1181 return d3dsp_register(D3DSPR_INPUT, i);
1183 for (i = 0; i < ARRAY_SIZE(writer->t_regnum); ++i)
1185 if(reg->regnum == writer->t_regnum[i])
1186 return d3dsp_register(D3DSPR_TEXTURE, i);
1189 WARN("Invalid ps 1/2 varying\n");
1190 writer->state = E_INVALIDARG;
1191 return 0;
1194 static void ps_1_0123_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1196 uint32_t token = 1u << 31;
1198 if (reg->rel_reg)
1200 WARN("Relative addressing not supported in <= ps_3_0\n");
1201 writer->state = E_INVALIDARG;
1202 return;
1205 switch (reg->type)
1207 case BWRITERSPR_INPUT:
1208 token |= map_ps_input(writer, reg);
1209 break;
1211 /* Take care about the texture temporaries. There's a problem: They aren't
1212 * declared anywhere, so we can only hardcode the values that are used
1213 * to map ps_1_3 shaders to the common shader structure
1215 case BWRITERSPR_TEMP:
1216 token |= map_ps13_temp(writer, reg);
1217 break;
1219 case BWRITERSPR_CONST: /* Can be mapped 1:1 */
1220 token |= d3dsp_register( reg->type, reg->regnum );
1221 break;
1223 default:
1224 WARN("Invalid register type for <= ps_1_3 shader\n");
1225 writer->state = E_INVALIDARG;
1226 return;
1229 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1231 if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW
1232 || reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG
1233 || reg->srcmod == BWRITERSPSM_NOT)
1235 WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
1236 writer->state = E_INVALIDARG;
1237 return;
1239 token |= d3d9_srcmod(reg->srcmod);
1240 put_u32(buffer, token);
1243 static void ps_1_0123_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1244 uint32_t shift, uint32_t mod)
1246 uint32_t token = (1u << 31); /* Bit 31 of registers is 1 */
1248 if (reg->rel_reg)
1250 WARN("Relative addressing not supported for destination registers\n");
1251 writer->state = E_INVALIDARG;
1252 return;
1255 switch (reg->type)
1257 case BWRITERSPR_TEMP:
1258 token |= map_ps13_temp(writer, reg);
1259 break;
1261 /* texkill uses the input register as a destination parameter */
1262 case BWRITERSPR_INPUT:
1263 token |= map_ps_input(writer, reg);
1264 break;
1266 default:
1267 WARN("Invalid dest register type for 1.x pshader\n");
1268 writer->state = E_INVALIDARG;
1269 return;
1272 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1273 token |= d3d9_dstmod(mod);
1275 token |= d3d9_writemask(reg->writemask);
1276 put_u32(buffer, token);
1279 /* The length of an instruction consists of the destination register (if any),
1280 * the number of source registers, the number of address registers used for
1281 * indirect addressing, and optionally the predicate register */
1282 static unsigned int instrlen(const struct instruction *instr, unsigned int srcs, unsigned int dsts)
1284 unsigned int ret = srcs + dsts + (instr->has_predicate ? 1 : 0);
1285 unsigned int i;
1287 if (dsts && instr->dst.rel_reg)
1288 ++ret;
1289 for (i = 0; i < srcs; ++i)
1290 if (instr->src[i].rel_reg)
1291 ++ret;
1292 return ret;
1295 static void sm_1_x_opcode(struct bc_writer *writer, const struct instruction *instr, uint32_t token,
1296 struct bytecode_buffer *buffer)
1298 /* Instruction length isn't encoded in sm_1_x. */
1299 if (instr->coissue)
1300 token |= D3DSI_COISSUE;
1301 put_u32(buffer, token);
1304 static void instr_handler(struct bc_writer *writer, const struct instruction *instr, struct bytecode_buffer *buffer)
1306 uint32_t token = d3d9_opcode(instr->opcode);
1308 writer->funcs->opcode(writer, instr, token, buffer);
1309 if (instr->has_dst)
1310 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1311 write_srcregs(writer, instr, buffer);
1314 static const struct instr_handler_table vs_1_x_handlers[] = {
1315 {BWRITERSIO_ADD, instr_handler},
1316 {BWRITERSIO_NOP, instr_handler},
1317 {BWRITERSIO_MOV, instr_handler},
1318 {BWRITERSIO_SUB, instr_handler},
1319 {BWRITERSIO_MAD, instr_handler},
1320 {BWRITERSIO_MUL, instr_handler},
1321 {BWRITERSIO_RCP, instr_handler},
1322 {BWRITERSIO_RSQ, instr_handler},
1323 {BWRITERSIO_DP3, instr_handler},
1324 {BWRITERSIO_DP4, instr_handler},
1325 {BWRITERSIO_MIN, instr_handler},
1326 {BWRITERSIO_MAX, instr_handler},
1327 {BWRITERSIO_SLT, instr_handler},
1328 {BWRITERSIO_SGE, instr_handler},
1329 {BWRITERSIO_EXP, instr_handler},
1330 {BWRITERSIO_LOG, instr_handler},
1331 {BWRITERSIO_EXPP, instr_handler},
1332 {BWRITERSIO_LOGP, instr_handler},
1333 {BWRITERSIO_DST, instr_handler},
1334 {BWRITERSIO_FRC, instr_handler},
1335 {BWRITERSIO_M4x4, instr_handler},
1336 {BWRITERSIO_M4x3, instr_handler},
1337 {BWRITERSIO_M3x4, instr_handler},
1338 {BWRITERSIO_M3x3, instr_handler},
1339 {BWRITERSIO_M3x2, instr_handler},
1340 {BWRITERSIO_LIT, instr_handler},
1342 {BWRITERSIO_END, NULL}, /* Sentinel value, it signals
1343 the end of the list */
1346 static const struct bytecode_backend vs_1_x_backend = {
1347 vs_1_x_header,
1348 end,
1349 vs_1_x_srcreg,
1350 vs_12_dstreg,
1351 sm_1_x_opcode,
1352 vs_1_x_handlers
1355 static void instr_ps_1_0123_texld(struct bc_writer *writer, const struct instruction *instr,
1356 struct bytecode_buffer *buffer)
1358 struct shader_reg reg;
1359 uint32_t swizzlemask;
1360 uint32_t idx;
1362 if (instr->src[1].type != BWRITERSPR_SAMPLER || instr->src[1].regnum > 3)
1364 WARN("Unsupported sampler type %u regnum %u.\n", instr->src[1].type, instr->src[1].regnum);
1365 writer->state = E_INVALIDARG;
1366 return;
1368 else if (instr->dst.type != BWRITERSPR_TEMP)
1370 WARN("Can only sample into a temp register\n");
1371 writer->state = E_INVALIDARG;
1372 return;
1375 idx = instr->src[1].regnum;
1376 if ((idx == 0 && instr->dst.regnum != T0_REG) || (idx == 1 && instr->dst.regnum != T1_REG)
1377 || (idx == 2 && instr->dst.regnum != T2_REG) || (idx == 3 && instr->dst.regnum != T3_REG))
1379 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n", idx, instr->dst.regnum);
1380 writer->state = E_INVALIDARG;
1381 return;
1383 if (instr->src[0].type == BWRITERSPR_INPUT)
1385 /* A simple non-dependent read tex instruction */
1386 if (instr->src[0].regnum != writer->t_regnum[idx])
1388 WARN("Cannot sample from s%u with texture address data from interpolator %u\n", idx, instr->src[0].regnum);
1389 writer->state = E_INVALIDARG;
1390 return;
1392 writer->funcs->opcode(writer, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1394 /* map the temp dstreg to the ps_1_3 texture temporary register */
1395 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1397 else if (instr->src[0].type == BWRITERSPR_TEMP)
1399 swizzlemask = 3 | (3 << 2) | (3 << 4);
1400 if ((instr->src[0].swizzle & swizzlemask) == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z))
1402 TRACE("writing texreg2rgb\n");
1403 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
1405 else if (instr->src[0].swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X))
1407 TRACE("writing texreg2ar\n");
1408 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
1410 else if (instr->src[0].swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z))
1412 TRACE("writing texreg2gb\n");
1413 writer->funcs->opcode(writer, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
1415 else
1417 WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].swizzle);
1418 writer->state = E_INVALIDARG;
1419 return;
1422 /* Dst and src reg can be mapped normally. Both registers are
1423 * temporary registers in the source shader and have to be mapped to
1424 * the temporary form of the texture registers. However, the src reg
1425 * doesn't have a swizzle. */
1426 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1427 reg = instr->src[0];
1428 reg.swizzle = BWRITERVS_NOSWIZZLE;
1429 writer->funcs->srcreg(writer, &reg, buffer);
1431 else
1433 WARN("Invalid address data source register\n");
1434 writer->state = E_INVALIDARG;
1435 return;
1439 static void instr_ps_1_0123_mov(struct bc_writer *writer, const struct instruction *instr,
1440 struct bytecode_buffer *buffer)
1442 uint32_t token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1444 if (instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT)
1446 if ((instr->dst.regnum == T0_REG && instr->src[0].regnum == writer->t_regnum[0])
1447 || (instr->dst.regnum == T1_REG && instr->src[0].regnum == writer->t_regnum[1])
1448 || (instr->dst.regnum == T2_REG && instr->src[0].regnum == writer->t_regnum[2])
1449 || (instr->dst.regnum == T3_REG && instr->src[0].regnum == writer->t_regnum[3]))
1451 if (instr->dstmod & BWRITERSPDM_SATURATE)
1453 writer->funcs->opcode(writer, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
1454 /* Remove the SATURATE flag, it's implicit to the instruction */
1455 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
1456 return;
1458 else
1460 WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
1461 writer->state = E_INVALIDARG;
1462 return;
1465 else if (instr->src[0].regnum == writer->v_regnum[0] || instr->src[0].regnum == writer->v_regnum[1])
1467 /* Handled by the normal mov below. Just drop out of the if condition */
1469 else
1471 WARN("Unsupported varying -> temp mov in <= ps_1_3\n");
1472 writer->state = E_INVALIDARG;
1473 return;
1477 writer->funcs->opcode(writer, instr, token, buffer);
1478 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1479 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1482 static const struct instr_handler_table ps_1_0123_handlers[] = {
1483 {BWRITERSIO_ADD, instr_handler},
1484 {BWRITERSIO_NOP, instr_handler},
1485 {BWRITERSIO_MOV, instr_ps_1_0123_mov},
1486 {BWRITERSIO_SUB, instr_handler},
1487 {BWRITERSIO_MAD, instr_handler},
1488 {BWRITERSIO_MUL, instr_handler},
1489 {BWRITERSIO_DP3, instr_handler},
1490 {BWRITERSIO_DP4, instr_handler},
1491 {BWRITERSIO_LRP, instr_handler},
1493 /* pshader instructions */
1494 {BWRITERSIO_CND, instr_handler},
1495 {BWRITERSIO_CMP, instr_handler},
1496 {BWRITERSIO_TEXKILL, instr_handler},
1497 {BWRITERSIO_TEX, instr_ps_1_0123_texld},
1498 {BWRITERSIO_TEXBEM, instr_handler},
1499 {BWRITERSIO_TEXBEML, instr_handler},
1500 {BWRITERSIO_TEXM3x2PAD, instr_handler},
1501 {BWRITERSIO_TEXM3x3PAD, instr_handler},
1502 {BWRITERSIO_TEXM3x3SPEC, instr_handler},
1503 {BWRITERSIO_TEXM3x3VSPEC, instr_handler},
1504 {BWRITERSIO_TEXM3x3TEX, instr_handler},
1505 {BWRITERSIO_TEXM3x3, instr_handler},
1506 {BWRITERSIO_TEXM3x2DEPTH, instr_handler},
1507 {BWRITERSIO_TEXM3x2TEX, instr_handler},
1508 {BWRITERSIO_TEXDP3, instr_handler},
1509 {BWRITERSIO_TEXDP3TEX, instr_handler},
1510 {BWRITERSIO_END, NULL},
1513 static const struct bytecode_backend ps_1_0123_backend = {
1514 ps_1_x_header,
1515 end,
1516 ps_1_0123_srcreg,
1517 ps_1_0123_dstreg,
1518 sm_1_x_opcode,
1519 ps_1_0123_handlers
1522 static void ps_1_4_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1524 uint32_t token = 1u << 31; /* Bit 31 of registers is 1. */
1526 if (reg->rel_reg)
1528 WARN("Relative addressing not supported in <= ps_3_0.\n");
1529 writer->state = E_INVALIDARG;
1530 return;
1533 switch (reg->type)
1535 case BWRITERSPR_INPUT:
1536 token |= map_ps_input(writer, reg);
1537 break;
1539 /* Can be mapped 1:1 */
1540 case BWRITERSPR_TEMP:
1541 case BWRITERSPR_CONST:
1542 token |= d3dsp_register( reg->type, reg->regnum );
1543 break;
1545 default:
1546 WARN("Invalid register type for ps_1_4 shader\n");
1547 writer->state = E_INVALIDARG;
1548 return;
1551 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1553 if (reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG || reg->srcmod == BWRITERSPSM_NOT)
1555 WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
1556 writer->state = E_INVALIDARG;
1557 return;
1559 token |= d3d9_srcmod(reg->srcmod);
1560 put_u32(buffer, token);
1563 static void ps_1_4_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
1564 uint32_t shift, uint32_t mod)
1566 uint32_t token = 1u << 31; /* Bit 31 of registers is 1. */
1568 if (reg->rel_reg)
1570 WARN("Relative addressing not supported for destination registers\n");
1571 writer->state = E_INVALIDARG;
1572 return;
1575 switch (reg->type)
1577 case BWRITERSPR_TEMP: /* 1:1 mapping */
1578 token |= d3dsp_register( reg->type, reg->regnum );
1579 break;
1581 /* For texkill */
1582 case BWRITERSPR_INPUT:
1583 token |= map_ps_input(writer, reg);
1584 break;
1586 default:
1587 WARN("Invalid dest register type for 1.x pshader\n");
1588 writer->state = E_INVALIDARG;
1589 return;
1592 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
1593 token |= d3d9_dstmod(mod);
1595 token |= d3d9_writemask(reg->writemask);
1596 put_u32(buffer, token);
1599 static void instr_ps_1_4_mov(struct bc_writer *writer, const struct instruction *instr,
1600 struct bytecode_buffer *buffer)
1602 uint32_t token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
1604 if (instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT)
1606 if (instr->src[0].regnum == writer->t_regnum[0] || instr->src[0].regnum == writer->t_regnum[1]
1607 || instr->src[0].regnum == writer->t_regnum[2] || instr->src[0].regnum == writer->t_regnum[3]
1608 || instr->src[0].regnum == writer->t_regnum[4] || instr->src[0].regnum == writer->t_regnum[5])
1610 /* Similar to a regular mov, but a different opcode */
1611 token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
1613 else if (instr->src[0].regnum == writer->v_regnum[0] || instr->src[0].regnum == writer->v_regnum[1])
1615 /* Handled by the normal mov below. Just drop out of the if condition */
1617 else
1619 WARN("Unsupported varying -> temp mov in ps_1_4\n");
1620 writer->state = E_INVALIDARG;
1621 return;
1625 writer->funcs->opcode(writer, instr, token, buffer);
1626 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1627 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1630 static void instr_ps_1_4_texld(struct bc_writer *writer, const struct instruction *instr,
1631 struct bytecode_buffer *buffer)
1633 if (instr->src[1].type != BWRITERSPR_SAMPLER || instr->src[1].regnum > 5)
1635 WARN("Unsupported sampler type %u regnum %u.\n",
1636 instr->src[1].type, instr->src[1].regnum);
1637 writer->state = E_INVALIDARG;
1638 return;
1640 else if (instr->dst.type != BWRITERSPR_TEMP)
1642 WARN("Can only sample into a temp register\n");
1643 writer->state = E_INVALIDARG;
1644 return;
1647 if (instr->src[1].regnum != instr->dst.regnum)
1649 WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4.\n",
1650 instr->src[1].regnum, instr->dst.regnum);
1651 writer->state = E_INVALIDARG;
1652 return;
1655 writer->funcs->opcode(writer, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
1656 writer->funcs->dstreg(writer, &instr->dst, buffer, instr->shift, instr->dstmod);
1657 writer->funcs->srcreg(writer, &instr->src[0], buffer);
1660 static const struct instr_handler_table ps_1_4_handlers[] = {
1661 {BWRITERSIO_ADD, instr_handler},
1662 {BWRITERSIO_NOP, instr_handler},
1663 {BWRITERSIO_MOV, instr_ps_1_4_mov},
1664 {BWRITERSIO_SUB, instr_handler},
1665 {BWRITERSIO_MAD, instr_handler},
1666 {BWRITERSIO_MUL, instr_handler},
1667 {BWRITERSIO_DP3, instr_handler},
1668 {BWRITERSIO_DP4, instr_handler},
1669 {BWRITERSIO_LRP, instr_handler},
1671 /* pshader instructions */
1672 {BWRITERSIO_CND, instr_handler},
1673 {BWRITERSIO_CMP, instr_handler},
1674 {BWRITERSIO_TEXKILL, instr_handler},
1675 {BWRITERSIO_TEX, instr_ps_1_4_texld},
1676 {BWRITERSIO_TEXDEPTH, instr_handler},
1677 {BWRITERSIO_BEM, instr_handler},
1679 {BWRITERSIO_PHASE, instr_handler},
1680 {BWRITERSIO_END, NULL},
1683 static const struct bytecode_backend ps_1_4_backend = {
1684 ps_1_4_header,
1685 end,
1686 ps_1_4_srcreg,
1687 ps_1_4_dstreg,
1688 sm_1_x_opcode,
1689 ps_1_4_handlers
1692 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1693 write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
1696 static void write_constI(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
1697 write_const(shader->constI, shader->num_ci, D3DSIO_DEFI, D3DSPR_CONSTINT, buffer, len);
1700 static void vs_2_header(struct bc_writer *This,
1701 const struct bwriter_shader *shader,
1702 struct bytecode_buffer *buffer) {
1703 HRESULT hr;
1705 hr = vs_find_builtin_varyings(This, shader);
1706 if(FAILED(hr)) {
1707 This->state = hr;
1708 return;
1711 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1712 write_constF(shader, buffer, TRUE);
1713 write_constB(shader, buffer, TRUE);
1714 write_constI(shader, buffer, TRUE);
1717 static void vs_2_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1719 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
1720 uint32_t component;
1721 uint32_t d3d9reg;
1722 BOOL has_swizzle;
1724 switch (reg->type)
1726 case BWRITERSPR_OUTPUT:
1727 /* Map the swizzle to a writemask, the format expected by
1728 * map_vs_output. */
1729 switch (reg->swizzle)
1731 case BWRITERVS_SWIZZLE_X:
1732 component = BWRITERSP_WRITEMASK_0;
1733 break;
1734 case BWRITERVS_SWIZZLE_Y:
1735 component = BWRITERSP_WRITEMASK_1;
1736 break;
1737 case BWRITERVS_SWIZZLE_Z:
1738 component = BWRITERSP_WRITEMASK_2;
1739 break;
1740 case BWRITERVS_SWIZZLE_W:
1741 component = BWRITERSP_WRITEMASK_3;
1742 break;
1743 default:
1744 component = 0;
1746 token |= map_vs_output(writer, reg->regnum, component, &has_swizzle);
1747 break;
1749 case BWRITERSPR_RASTOUT:
1750 case BWRITERSPR_ATTROUT:
1751 /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
1752 * but are unexpected. If we hit this path it might be due to an error.
1754 FIXME("Unexpected register type %u.\n", reg->type);
1755 /* drop through */
1756 case BWRITERSPR_INPUT:
1757 case BWRITERSPR_TEMP:
1758 case BWRITERSPR_CONST:
1759 case BWRITERSPR_ADDR:
1760 case BWRITERSPR_CONSTINT:
1761 case BWRITERSPR_CONSTBOOL:
1762 case BWRITERSPR_LABEL:
1763 d3d9reg = d3d9_register(reg->type);
1764 token |= d3dsp_register(d3d9reg, reg->regnum);
1765 break;
1767 case BWRITERSPR_LOOP:
1768 if (reg->regnum != 0)
1770 WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
1771 writer->state = E_INVALIDARG;
1772 return;
1774 token |= d3dsp_register(D3DSPR_LOOP, 0);
1775 break;
1777 case BWRITERSPR_PREDICATE:
1778 if (writer->shader->major_version != 2 || writer->shader->minor_version != 1)
1780 WARN("Predicate register is allowed only in vs_2_x\n");
1781 writer->state = E_INVALIDARG;
1782 return;
1784 if (reg->regnum > 0)
1786 WARN("Only predicate register 0 is supported\n");
1787 writer->state = E_INVALIDARG;
1788 return;
1790 token |= d3dsp_register(D3DSPR_PREDICATE, 0);
1791 break;
1793 default:
1794 WARN("Invalid register type for 2.0 vshader\n");
1795 writer->state = E_INVALIDARG;
1796 return;
1799 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
1800 token |= d3d9_srcmod(reg->srcmod);
1802 if (reg->rel_reg)
1803 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
1805 put_u32(buffer, token);
1807 /* vs_2_0 and newer write the register containing the index explicitly in
1808 * the binary code. */
1809 if (token & D3DVS_ADDRMODE_RELATIVE)
1810 vs_2_srcreg(writer, reg->rel_reg, buffer);
1813 static void sm_2_opcode(struct bc_writer *writer, const struct instruction *instr, uint32_t token,
1814 struct bytecode_buffer *buffer)
1816 unsigned int dst_count = instr->has_dst ? 1 : 0;
1818 /* From SM 2 onwards instruction length is encoded in the opcode field. */
1819 token |= instrlen(instr, instr->num_srcs, dst_count) << D3DSI_INSTLENGTH_SHIFT;
1820 if (instr->comptype)
1821 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
1822 if (instr->has_predicate)
1823 token |= D3DSHADER_INSTRUCTION_PREDICATED;
1824 put_u32(buffer,token);
1827 static const struct instr_handler_table vs_2_0_handlers[] = {
1828 {BWRITERSIO_ADD, instr_handler},
1829 {BWRITERSIO_NOP, instr_handler},
1830 {BWRITERSIO_MOV, instr_handler},
1831 {BWRITERSIO_SUB, instr_handler},
1832 {BWRITERSIO_MAD, instr_handler},
1833 {BWRITERSIO_MUL, instr_handler},
1834 {BWRITERSIO_RCP, instr_handler},
1835 {BWRITERSIO_RSQ, instr_handler},
1836 {BWRITERSIO_DP3, instr_handler},
1837 {BWRITERSIO_DP4, instr_handler},
1838 {BWRITERSIO_MIN, instr_handler},
1839 {BWRITERSIO_MAX, instr_handler},
1840 {BWRITERSIO_SLT, instr_handler},
1841 {BWRITERSIO_SGE, instr_handler},
1842 {BWRITERSIO_ABS, instr_handler},
1843 {BWRITERSIO_EXP, instr_handler},
1844 {BWRITERSIO_LOG, instr_handler},
1845 {BWRITERSIO_EXPP, instr_handler},
1846 {BWRITERSIO_LOGP, instr_handler},
1847 {BWRITERSIO_DST, instr_handler},
1848 {BWRITERSIO_LRP, instr_handler},
1849 {BWRITERSIO_FRC, instr_handler},
1850 {BWRITERSIO_CRS, instr_handler},
1851 {BWRITERSIO_SGN, instr_handler},
1852 {BWRITERSIO_NRM, instr_handler},
1853 {BWRITERSIO_SINCOS, instr_handler},
1854 {BWRITERSIO_M4x4, instr_handler},
1855 {BWRITERSIO_M4x3, instr_handler},
1856 {BWRITERSIO_M3x4, instr_handler},
1857 {BWRITERSIO_M3x3, instr_handler},
1858 {BWRITERSIO_M3x2, instr_handler},
1859 {BWRITERSIO_LIT, instr_handler},
1860 {BWRITERSIO_POW, instr_handler},
1861 {BWRITERSIO_MOVA, instr_handler},
1863 {BWRITERSIO_CALL, instr_handler},
1864 {BWRITERSIO_CALLNZ, instr_handler},
1865 {BWRITERSIO_REP, instr_handler},
1866 {BWRITERSIO_ENDREP, instr_handler},
1867 {BWRITERSIO_IF, instr_handler},
1868 {BWRITERSIO_LABEL, instr_handler},
1869 {BWRITERSIO_ELSE, instr_handler},
1870 {BWRITERSIO_ENDIF, instr_handler},
1871 {BWRITERSIO_LOOP, instr_handler},
1872 {BWRITERSIO_RET, instr_handler},
1873 {BWRITERSIO_ENDLOOP, instr_handler},
1875 {BWRITERSIO_END, NULL},
1878 static const struct bytecode_backend vs_2_0_backend = {
1879 vs_2_header,
1880 end,
1881 vs_2_srcreg,
1882 vs_12_dstreg,
1883 sm_2_opcode,
1884 vs_2_0_handlers
1887 static const struct instr_handler_table vs_2_x_handlers[] = {
1888 {BWRITERSIO_ADD, instr_handler},
1889 {BWRITERSIO_NOP, instr_handler},
1890 {BWRITERSIO_MOV, instr_handler},
1891 {BWRITERSIO_SUB, instr_handler},
1892 {BWRITERSIO_MAD, instr_handler},
1893 {BWRITERSIO_MUL, instr_handler},
1894 {BWRITERSIO_RCP, instr_handler},
1895 {BWRITERSIO_RSQ, instr_handler},
1896 {BWRITERSIO_DP3, instr_handler},
1897 {BWRITERSIO_DP4, instr_handler},
1898 {BWRITERSIO_MIN, instr_handler},
1899 {BWRITERSIO_MAX, instr_handler},
1900 {BWRITERSIO_SLT, instr_handler},
1901 {BWRITERSIO_SGE, instr_handler},
1902 {BWRITERSIO_ABS, instr_handler},
1903 {BWRITERSIO_EXP, instr_handler},
1904 {BWRITERSIO_LOG, instr_handler},
1905 {BWRITERSIO_EXPP, instr_handler},
1906 {BWRITERSIO_LOGP, instr_handler},
1907 {BWRITERSIO_DST, instr_handler},
1908 {BWRITERSIO_LRP, instr_handler},
1909 {BWRITERSIO_FRC, instr_handler},
1910 {BWRITERSIO_CRS, instr_handler},
1911 {BWRITERSIO_SGN, instr_handler},
1912 {BWRITERSIO_NRM, instr_handler},
1913 {BWRITERSIO_SINCOS, instr_handler},
1914 {BWRITERSIO_M4x4, instr_handler},
1915 {BWRITERSIO_M4x3, instr_handler},
1916 {BWRITERSIO_M3x4, instr_handler},
1917 {BWRITERSIO_M3x3, instr_handler},
1918 {BWRITERSIO_M3x2, instr_handler},
1919 {BWRITERSIO_LIT, instr_handler},
1920 {BWRITERSIO_POW, instr_handler},
1921 {BWRITERSIO_MOVA, instr_handler},
1923 {BWRITERSIO_CALL, instr_handler},
1924 {BWRITERSIO_CALLNZ, instr_handler},
1925 {BWRITERSIO_REP, instr_handler},
1926 {BWRITERSIO_ENDREP, instr_handler},
1927 {BWRITERSIO_IF, instr_handler},
1928 {BWRITERSIO_LABEL, instr_handler},
1929 {BWRITERSIO_IFC, instr_handler},
1930 {BWRITERSIO_ELSE, instr_handler},
1931 {BWRITERSIO_ENDIF, instr_handler},
1932 {BWRITERSIO_BREAK, instr_handler},
1933 {BWRITERSIO_BREAKC, instr_handler},
1934 {BWRITERSIO_LOOP, instr_handler},
1935 {BWRITERSIO_RET, instr_handler},
1936 {BWRITERSIO_ENDLOOP, instr_handler},
1938 {BWRITERSIO_SETP, instr_handler},
1939 {BWRITERSIO_BREAKP, instr_handler},
1941 {BWRITERSIO_END, NULL},
1944 static const struct bytecode_backend vs_2_x_backend = {
1945 vs_2_header,
1946 end,
1947 vs_2_srcreg,
1948 vs_12_dstreg,
1949 sm_2_opcode,
1950 vs_2_x_handlers
1953 static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer)
1955 const uint32_t reg = (1u << 31) | d3dsp_register(D3DSPR_SAMPLER, 0) | D3DSP_WRITEMASK_ALL;
1956 uint32_t instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
1957 unsigned int i;
1958 uint32_t token;
1960 for (i = 0; i < shader->num_samplers; ++i)
1962 /* Write the DCL instruction */
1963 put_u32(buffer, instr_dcl);
1964 token = 1u << 31;
1965 /* Already shifted */
1966 token |= d3d9_sampler(shader->samplers[i].type) & D3DSP_TEXTURETYPE_MASK;
1967 put_u32(buffer, token);
1968 token = reg | (shader->samplers[i].regnum & D3DSP_REGNUM_MASK);
1969 token |= d3d9_dstmod(shader->samplers[i].mod);
1970 put_u32(buffer, token);
1974 static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
1975 HRESULT hr = find_ps_builtin_semantics(This, shader, 8);
1976 if(FAILED(hr)) {
1977 This->state = hr;
1978 return;
1981 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
1982 write_samplers(shader, buffer);
1983 write_constF(shader, buffer, TRUE);
1984 write_constB(shader, buffer, TRUE);
1985 write_constI(shader, buffer, TRUE);
1988 static void ps_2_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
1990 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
1991 uint32_t d3d9reg;
1993 if (reg->rel_reg)
1995 WARN("Relative addressing not supported in <= ps_3_0\n");
1996 writer->state = E_INVALIDARG;
1997 return;
2000 switch (reg->type)
2002 case BWRITERSPR_INPUT:
2003 token |= map_ps_input(writer, reg);
2004 break;
2006 /* Can be mapped 1:1 */
2007 case BWRITERSPR_TEMP:
2008 case BWRITERSPR_CONST:
2009 case BWRITERSPR_COLOROUT:
2010 case BWRITERSPR_CONSTBOOL:
2011 case BWRITERSPR_CONSTINT:
2012 case BWRITERSPR_SAMPLER:
2013 case BWRITERSPR_LABEL:
2014 case BWRITERSPR_DEPTHOUT:
2015 d3d9reg = d3d9_register(reg->type);
2016 token |= d3dsp_register(d3d9reg, reg->regnum);
2017 break;
2019 case BWRITERSPR_PREDICATE:
2020 if (writer->shader->minor_version == 0)
2022 WARN("Predicate register not supported in ps_2_0\n");
2023 writer->state = E_INVALIDARG;
2025 if (reg->regnum)
2027 WARN("Predicate register with regnum %u not supported.\n", reg->regnum);
2028 writer->state = E_INVALIDARG;
2030 token |= d3dsp_register(D3DSPR_PREDICATE, 0);
2031 break;
2033 default:
2034 WARN("Invalid register type for ps_2_0 shader\n");
2035 writer->state = E_INVALIDARG;
2036 return;
2039 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
2041 token |= d3d9_srcmod(reg->srcmod);
2042 put_u32(buffer, token);
2045 static void ps_2_0_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
2046 uint32_t shift, uint32_t mod)
2048 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2049 uint32_t d3d9reg;
2051 if (reg->rel_reg)
2053 WARN("Relative addressing not supported for destination registers\n");
2054 writer->state = E_INVALIDARG;
2055 return;
2058 switch (reg->type)
2060 case BWRITERSPR_TEMP: /* 1:1 mapping */
2061 case BWRITERSPR_COLOROUT:
2062 case BWRITERSPR_DEPTHOUT:
2063 d3d9reg = d3d9_register(reg->type);
2064 token |= d3dsp_register(d3d9reg, reg->regnum);
2065 break;
2067 case BWRITERSPR_PREDICATE:
2068 if (writer->shader->minor_version == 0)
2070 WARN("Predicate register not supported in ps_2_0\n");
2071 writer->state = E_INVALIDARG;
2073 token |= d3dsp_register(D3DSPR_PREDICATE, reg->regnum);
2074 break;
2076 /* texkill uses the input register as a destination parameter */
2077 case BWRITERSPR_INPUT:
2078 token |= map_ps_input(writer, reg);
2079 break;
2081 default:
2082 WARN("Invalid dest register type for 2.x pshader\n");
2083 writer->state = E_INVALIDARG;
2084 return;
2087 token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
2088 token |= d3d9_dstmod(mod);
2090 token |= d3d9_writemask(reg->writemask);
2091 put_u32(buffer, token);
2094 static const struct instr_handler_table ps_2_0_handlers[] = {
2095 {BWRITERSIO_ADD, instr_handler},
2096 {BWRITERSIO_NOP, instr_handler},
2097 {BWRITERSIO_MOV, instr_handler},
2098 {BWRITERSIO_SUB, instr_handler},
2099 {BWRITERSIO_MAD, instr_handler},
2100 {BWRITERSIO_MUL, instr_handler},
2101 {BWRITERSIO_RCP, instr_handler},
2102 {BWRITERSIO_RSQ, instr_handler},
2103 {BWRITERSIO_DP3, instr_handler},
2104 {BWRITERSIO_DP4, instr_handler},
2105 {BWRITERSIO_MIN, instr_handler},
2106 {BWRITERSIO_MAX, instr_handler},
2107 {BWRITERSIO_ABS, instr_handler},
2108 {BWRITERSIO_EXP, instr_handler},
2109 {BWRITERSIO_LOG, instr_handler},
2110 {BWRITERSIO_EXPP, instr_handler},
2111 {BWRITERSIO_LOGP, instr_handler},
2112 {BWRITERSIO_LRP, instr_handler},
2113 {BWRITERSIO_FRC, instr_handler},
2114 {BWRITERSIO_CRS, instr_handler},
2115 {BWRITERSIO_NRM, instr_handler},
2116 {BWRITERSIO_SINCOS, instr_handler},
2117 {BWRITERSIO_M4x4, instr_handler},
2118 {BWRITERSIO_M4x3, instr_handler},
2119 {BWRITERSIO_M3x4, instr_handler},
2120 {BWRITERSIO_M3x3, instr_handler},
2121 {BWRITERSIO_M3x2, instr_handler},
2122 {BWRITERSIO_POW, instr_handler},
2123 {BWRITERSIO_DP2ADD, instr_handler},
2124 {BWRITERSIO_CMP, instr_handler},
2126 {BWRITERSIO_TEX, instr_handler},
2127 {BWRITERSIO_TEXLDP, instr_handler},
2128 {BWRITERSIO_TEXLDB, instr_handler},
2129 {BWRITERSIO_TEXKILL, instr_handler},
2131 {BWRITERSIO_END, NULL},
2134 static const struct bytecode_backend ps_2_0_backend = {
2135 ps_2_header,
2136 end,
2137 ps_2_srcreg,
2138 ps_2_0_dstreg,
2139 sm_2_opcode,
2140 ps_2_0_handlers
2143 static const struct instr_handler_table ps_2_x_handlers[] = {
2144 {BWRITERSIO_ADD, instr_handler},
2145 {BWRITERSIO_NOP, instr_handler},
2146 {BWRITERSIO_MOV, instr_handler},
2147 {BWRITERSIO_SUB, instr_handler},
2148 {BWRITERSIO_MAD, instr_handler},
2149 {BWRITERSIO_MUL, instr_handler},
2150 {BWRITERSIO_RCP, instr_handler},
2151 {BWRITERSIO_RSQ, instr_handler},
2152 {BWRITERSIO_DP3, instr_handler},
2153 {BWRITERSIO_DP4, instr_handler},
2154 {BWRITERSIO_MIN, instr_handler},
2155 {BWRITERSIO_MAX, instr_handler},
2156 {BWRITERSIO_ABS, instr_handler},
2157 {BWRITERSIO_EXP, instr_handler},
2158 {BWRITERSIO_LOG, instr_handler},
2159 {BWRITERSIO_EXPP, instr_handler},
2160 {BWRITERSIO_LOGP, instr_handler},
2161 {BWRITERSIO_LRP, instr_handler},
2162 {BWRITERSIO_FRC, instr_handler},
2163 {BWRITERSIO_CRS, instr_handler},
2164 {BWRITERSIO_NRM, instr_handler},
2165 {BWRITERSIO_SINCOS, instr_handler},
2166 {BWRITERSIO_M4x4, instr_handler},
2167 {BWRITERSIO_M4x3, instr_handler},
2168 {BWRITERSIO_M3x4, instr_handler},
2169 {BWRITERSIO_M3x3, instr_handler},
2170 {BWRITERSIO_M3x2, instr_handler},
2171 {BWRITERSIO_POW, instr_handler},
2172 {BWRITERSIO_DP2ADD, instr_handler},
2173 {BWRITERSIO_CMP, instr_handler},
2175 {BWRITERSIO_CALL, instr_handler},
2176 {BWRITERSIO_CALLNZ, instr_handler},
2177 {BWRITERSIO_REP, instr_handler},
2178 {BWRITERSIO_ENDREP, instr_handler},
2179 {BWRITERSIO_IF, instr_handler},
2180 {BWRITERSIO_LABEL, instr_handler},
2181 {BWRITERSIO_IFC, instr_handler},
2182 {BWRITERSIO_ELSE, instr_handler},
2183 {BWRITERSIO_ENDIF, instr_handler},
2184 {BWRITERSIO_BREAK, instr_handler},
2185 {BWRITERSIO_BREAKC, instr_handler},
2186 {BWRITERSIO_RET, instr_handler},
2188 {BWRITERSIO_TEX, instr_handler},
2189 {BWRITERSIO_TEXLDP, instr_handler},
2190 {BWRITERSIO_TEXLDB, instr_handler},
2191 {BWRITERSIO_TEXKILL, instr_handler},
2192 {BWRITERSIO_DSX, instr_handler},
2193 {BWRITERSIO_DSY, instr_handler},
2195 {BWRITERSIO_SETP, instr_handler},
2196 {BWRITERSIO_BREAKP, instr_handler},
2198 {BWRITERSIO_TEXLDD, instr_handler},
2200 {BWRITERSIO_END, NULL},
2203 static const struct bytecode_backend ps_2_x_backend = {
2204 ps_2_header,
2205 end,
2206 ps_2_srcreg,
2207 ps_2_0_dstreg,
2208 sm_2_opcode,
2209 ps_2_x_handlers
2212 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
2213 write_declarations(This, buffer, shader->inputs, shader->num_inputs, BWRITERSPR_INPUT);
2214 write_declarations(This, buffer, shader->outputs, shader->num_outputs, BWRITERSPR_OUTPUT);
2215 write_constF(shader, buffer, TRUE);
2216 write_constB(shader, buffer, TRUE);
2217 write_constI(shader, buffer, TRUE);
2218 write_samplers(shader, buffer);
2221 static void sm_3_srcreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer)
2223 const struct bwriter_shader *shader = writer->shader;
2224 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2225 uint32_t d3d9reg;
2227 d3d9reg = d3d9_register(reg->type);
2228 token |= d3dsp_register(d3d9reg, reg->regnum);
2229 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
2230 token |= d3d9_srcmod(reg->srcmod);
2232 if (reg->rel_reg)
2234 if (reg->type == BWRITERSPR_CONST && shader->type == ST_PIXEL)
2236 WARN("c%u[...] is unsupported in ps_3_0.\n", reg->regnum);
2237 writer->state = E_INVALIDARG;
2238 return;
2241 if (((reg->rel_reg->type == BWRITERSPR_ADDR && shader->type == ST_VERTEX)
2242 || reg->rel_reg->type == BWRITERSPR_LOOP) && reg->rel_reg->regnum == 0)
2244 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2246 else
2248 WARN("Unsupported relative addressing register\n");
2249 writer->state = E_INVALIDARG;
2250 return;
2254 put_u32(buffer, token);
2256 /* vs_2_0 and newer write the register containing the index explicitly in
2257 * the binary code. */
2258 if (token & D3DVS_ADDRMODE_RELATIVE)
2259 sm_3_srcreg(writer, reg->rel_reg, buffer);
2262 static void sm_3_dstreg(struct bc_writer *writer, const struct shader_reg *reg, struct bytecode_buffer *buffer,
2263 uint32_t shift, uint32_t mod)
2265 const struct bwriter_shader *shader = writer->shader;
2266 uint32_t token = 1u << 31; /* Bit 31 of registers is 1 */
2267 uint32_t d3d9reg;
2269 if (reg->rel_reg)
2271 if (shader->type == ST_VERTEX && reg->type == BWRITERSPR_OUTPUT)
2273 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
2275 else
2277 WARN("Relative addressing not supported for this shader type or register type\n");
2278 writer->state = E_INVALIDARG;
2279 return;
2283 d3d9reg = d3d9_register(reg->type);
2284 token |= d3dsp_register(d3d9reg, reg->regnum);
2285 token |= d3d9_dstmod(mod);
2286 token |= d3d9_writemask(reg->writemask);
2287 put_u32(buffer, token);
2289 /* vs_2_0 and newer write the register containing the index explicitly in
2290 * the binary code. */
2291 if (token & D3DVS_ADDRMODE_RELATIVE)
2292 sm_3_srcreg(writer, reg->rel_reg, buffer);
2295 static const struct instr_handler_table vs_3_handlers[] = {
2296 {BWRITERSIO_ADD, instr_handler},
2297 {BWRITERSIO_NOP, instr_handler},
2298 {BWRITERSIO_MOV, instr_handler},
2299 {BWRITERSIO_SUB, instr_handler},
2300 {BWRITERSIO_MAD, instr_handler},
2301 {BWRITERSIO_MUL, instr_handler},
2302 {BWRITERSIO_RCP, instr_handler},
2303 {BWRITERSIO_RSQ, instr_handler},
2304 {BWRITERSIO_DP3, instr_handler},
2305 {BWRITERSIO_DP4, instr_handler},
2306 {BWRITERSIO_MIN, instr_handler},
2307 {BWRITERSIO_MAX, instr_handler},
2308 {BWRITERSIO_SLT, instr_handler},
2309 {BWRITERSIO_SGE, instr_handler},
2310 {BWRITERSIO_ABS, instr_handler},
2311 {BWRITERSIO_EXP, instr_handler},
2312 {BWRITERSIO_LOG, instr_handler},
2313 {BWRITERSIO_EXPP, instr_handler},
2314 {BWRITERSIO_LOGP, instr_handler},
2315 {BWRITERSIO_DST, instr_handler},
2316 {BWRITERSIO_LRP, instr_handler},
2317 {BWRITERSIO_FRC, instr_handler},
2318 {BWRITERSIO_CRS, instr_handler},
2319 {BWRITERSIO_SGN, instr_handler},
2320 {BWRITERSIO_NRM, instr_handler},
2321 {BWRITERSIO_SINCOS, instr_handler},
2322 {BWRITERSIO_M4x4, instr_handler},
2323 {BWRITERSIO_M4x3, instr_handler},
2324 {BWRITERSIO_M3x4, instr_handler},
2325 {BWRITERSIO_M3x3, instr_handler},
2326 {BWRITERSIO_M3x2, instr_handler},
2327 {BWRITERSIO_LIT, instr_handler},
2328 {BWRITERSIO_POW, instr_handler},
2329 {BWRITERSIO_MOVA, instr_handler},
2331 {BWRITERSIO_CALL, instr_handler},
2332 {BWRITERSIO_CALLNZ, instr_handler},
2333 {BWRITERSIO_REP, instr_handler},
2334 {BWRITERSIO_ENDREP, instr_handler},
2335 {BWRITERSIO_IF, instr_handler},
2336 {BWRITERSIO_LABEL, instr_handler},
2337 {BWRITERSIO_IFC, instr_handler},
2338 {BWRITERSIO_ELSE, instr_handler},
2339 {BWRITERSIO_ENDIF, instr_handler},
2340 {BWRITERSIO_BREAK, instr_handler},
2341 {BWRITERSIO_BREAKC, instr_handler},
2342 {BWRITERSIO_LOOP, instr_handler},
2343 {BWRITERSIO_RET, instr_handler},
2344 {BWRITERSIO_ENDLOOP, instr_handler},
2346 {BWRITERSIO_SETP, instr_handler},
2347 {BWRITERSIO_BREAKP, instr_handler},
2348 {BWRITERSIO_TEXLDL, instr_handler},
2350 {BWRITERSIO_END, NULL},
2353 static const struct bytecode_backend vs_3_backend = {
2354 sm_3_header,
2355 end,
2356 sm_3_srcreg,
2357 sm_3_dstreg,
2358 sm_2_opcode,
2359 vs_3_handlers
2362 static const struct instr_handler_table ps_3_handlers[] = {
2363 {BWRITERSIO_ADD, instr_handler},
2364 {BWRITERSIO_NOP, instr_handler},
2365 {BWRITERSIO_MOV, instr_handler},
2366 {BWRITERSIO_SUB, instr_handler},
2367 {BWRITERSIO_MAD, instr_handler},
2368 {BWRITERSIO_MUL, instr_handler},
2369 {BWRITERSIO_RCP, instr_handler},
2370 {BWRITERSIO_RSQ, instr_handler},
2371 {BWRITERSIO_DP3, instr_handler},
2372 {BWRITERSIO_DP4, instr_handler},
2373 {BWRITERSIO_MIN, instr_handler},
2374 {BWRITERSIO_MAX, instr_handler},
2375 {BWRITERSIO_ABS, instr_handler},
2376 {BWRITERSIO_EXP, instr_handler},
2377 {BWRITERSIO_LOG, instr_handler},
2378 {BWRITERSIO_EXPP, instr_handler},
2379 {BWRITERSIO_LOGP, instr_handler},
2380 {BWRITERSIO_LRP, instr_handler},
2381 {BWRITERSIO_FRC, instr_handler},
2382 {BWRITERSIO_CRS, instr_handler},
2383 {BWRITERSIO_NRM, instr_handler},
2384 {BWRITERSIO_SINCOS, instr_handler},
2385 {BWRITERSIO_M4x4, instr_handler},
2386 {BWRITERSIO_M4x3, instr_handler},
2387 {BWRITERSIO_M3x4, instr_handler},
2388 {BWRITERSIO_M3x3, instr_handler},
2389 {BWRITERSIO_M3x2, instr_handler},
2390 {BWRITERSIO_POW, instr_handler},
2391 {BWRITERSIO_DP2ADD, instr_handler},
2392 {BWRITERSIO_CMP, instr_handler},
2394 {BWRITERSIO_CALL, instr_handler},
2395 {BWRITERSIO_CALLNZ, instr_handler},
2396 {BWRITERSIO_REP, instr_handler},
2397 {BWRITERSIO_ENDREP, instr_handler},
2398 {BWRITERSIO_IF, instr_handler},
2399 {BWRITERSIO_LABEL, instr_handler},
2400 {BWRITERSIO_IFC, instr_handler},
2401 {BWRITERSIO_ELSE, instr_handler},
2402 {BWRITERSIO_ENDIF, instr_handler},
2403 {BWRITERSIO_BREAK, instr_handler},
2404 {BWRITERSIO_BREAKC, instr_handler},
2405 {BWRITERSIO_LOOP, instr_handler},
2406 {BWRITERSIO_RET, instr_handler},
2407 {BWRITERSIO_ENDLOOP, instr_handler},
2409 {BWRITERSIO_SETP, instr_handler},
2410 {BWRITERSIO_BREAKP, instr_handler},
2411 {BWRITERSIO_TEXLDL, instr_handler},
2413 {BWRITERSIO_TEX, instr_handler},
2414 {BWRITERSIO_TEXLDP, instr_handler},
2415 {BWRITERSIO_TEXLDB, instr_handler},
2416 {BWRITERSIO_TEXKILL, instr_handler},
2417 {BWRITERSIO_DSX, instr_handler},
2418 {BWRITERSIO_DSY, instr_handler},
2419 {BWRITERSIO_TEXLDD, instr_handler},
2421 {BWRITERSIO_END, NULL},
2424 static const struct bytecode_backend ps_3_backend = {
2425 sm_3_header,
2426 end,
2427 sm_3_srcreg,
2428 sm_3_dstreg,
2429 sm_2_opcode,
2430 ps_3_handlers
2433 static const struct
2435 enum shader_type type;
2436 unsigned char major, minor;
2437 const struct bytecode_backend *backend;
2439 shader_backends[] =
2441 {ST_VERTEX, 1, 0, &vs_1_x_backend},
2442 {ST_VERTEX, 1, 1, &vs_1_x_backend},
2443 {ST_VERTEX, 2, 0, &vs_2_0_backend},
2444 {ST_VERTEX, 2, 1, &vs_2_x_backend},
2445 {ST_VERTEX, 3, 0, &vs_3_backend},
2447 {ST_PIXEL, 1, 0, &ps_1_0123_backend},
2448 {ST_PIXEL, 1, 1, &ps_1_0123_backend},
2449 {ST_PIXEL, 1, 2, &ps_1_0123_backend},
2450 {ST_PIXEL, 1, 3, &ps_1_0123_backend},
2451 {ST_PIXEL, 1, 4, &ps_1_4_backend},
2452 {ST_PIXEL, 2, 0, &ps_2_0_backend},
2453 {ST_PIXEL, 2, 1, &ps_2_x_backend},
2454 {ST_PIXEL, 3, 0, &ps_3_backend},
2457 static HRESULT call_instr_handler(struct bc_writer *writer, const struct instruction *instr,
2458 struct bytecode_buffer *buffer)
2460 unsigned int i;
2462 for (i = 0; writer->funcs->instructions[i].opcode != BWRITERSIO_END; ++i)
2464 if (instr->opcode == writer->funcs->instructions[i].opcode)
2466 if (!writer->funcs->instructions[i].func)
2468 WARN("Opcode %u not supported by this profile.\n", instr->opcode);
2469 return E_INVALIDARG;
2471 writer->funcs->instructions[i].func(writer, instr, buffer);
2472 return S_OK;
2476 FIXME("Unhandled instruction %u - %s.\n", instr->opcode, debug_print_opcode(instr->opcode));
2477 return E_INVALIDARG;
2480 HRESULT shader_write_bytecode(const struct bwriter_shader *shader, uint32_t **result, uint32_t *size)
2482 struct bc_writer *writer;
2483 struct bytecode_buffer *buffer = NULL;
2484 HRESULT hr;
2485 unsigned int i;
2487 if(!shader){
2488 ERR("NULL shader structure, aborting\n");
2489 return E_FAIL;
2492 if (!(writer = d3dcompiler_alloc(sizeof(*writer))))
2493 return E_OUTOFMEMORY;
2495 for (i = 0; i < ARRAY_SIZE(shader_backends); ++i)
2497 if (shader->type == shader_backends[i].type
2498 && shader->major_version == shader_backends[i].major
2499 && shader->minor_version == shader_backends[i].minor)
2501 writer->funcs = shader_backends[i].backend;
2502 break;
2506 if (!writer->funcs)
2508 FIXME("Unsupported shader type %#x, version %u.%u.\n",
2509 shader->type, shader->major_version, shader->minor_version);
2510 d3dcompiler_free(writer);
2511 return E_NOTIMPL;
2514 writer->shader = shader;
2515 *result = NULL;
2517 buffer = allocate_buffer();
2518 if(!buffer) {
2519 WARN("Failed to allocate a buffer for the shader bytecode\n");
2520 hr = E_FAIL;
2521 goto error;
2524 /* Write shader type and version */
2525 put_u32(buffer, sm1_version(shader));
2527 writer->funcs->header(writer, shader, buffer);
2528 if(FAILED(writer->state)) {
2529 hr = writer->state;
2530 goto error;
2533 for(i = 0; i < shader->num_instrs; i++) {
2534 hr = call_instr_handler(writer, shader->instr[i], buffer);
2535 if(FAILED(hr)) {
2536 goto error;
2540 if(FAILED(writer->state)) {
2541 hr = writer->state;
2542 goto error;
2545 writer->funcs->end(writer, shader, buffer);
2547 if(FAILED(buffer->state)) {
2548 hr = buffer->state;
2549 goto error;
2552 *size = buffer->size * sizeof(uint32_t);
2553 *result = buffer->data;
2554 buffer->data = NULL;
2555 hr = S_OK;
2557 error:
2558 if(buffer) {
2559 d3dcompiler_free(buffer->data);
2560 d3dcompiler_free(buffer);
2562 d3dcompiler_free(writer);
2563 return hr;
2566 void SlDeleteShader(struct bwriter_shader *shader) {
2567 unsigned int i, j;
2569 TRACE("Deleting shader %p\n", shader);
2571 for(i = 0; i < shader->num_cf; i++) {
2572 d3dcompiler_free(shader->constF[i]);
2574 d3dcompiler_free(shader->constF);
2575 for(i = 0; i < shader->num_ci; i++) {
2576 d3dcompiler_free(shader->constI[i]);
2578 d3dcompiler_free(shader->constI);
2579 for(i = 0; i < shader->num_cb; i++) {
2580 d3dcompiler_free(shader->constB[i]);
2582 d3dcompiler_free(shader->constB);
2584 d3dcompiler_free(shader->inputs);
2585 d3dcompiler_free(shader->outputs);
2586 d3dcompiler_free(shader->samplers);
2588 for(i = 0; i < shader->num_instrs; i++) {
2589 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
2590 d3dcompiler_free(shader->instr[i]->src[j].rel_reg);
2592 d3dcompiler_free(shader->instr[i]->src);
2593 d3dcompiler_free(shader->instr[i]->dst.rel_reg);
2594 d3dcompiler_free(shader->instr[i]);
2596 d3dcompiler_free(shader->instr);
2598 d3dcompiler_free(shader);