2 * Copyright 2008 Stefan Dösinger
3 * Copyright 2009 Matteo Bruni
4 * Copyright 2008-2009 Henri Verbeet for CodeWeavers
5 * Copyright 2010 Rico Schüller
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
26 #include "d3dcompiler_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler);
30 #define WINE_D3DCOMPILER_TO_STR(x) case x: return #x
32 const char *debug_d3dcompiler_d3d_blob_part(D3D_BLOB_PART part)
36 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_INPUT_SIGNATURE_BLOB);
37 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_OUTPUT_SIGNATURE_BLOB);
38 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB);
39 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB);
40 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_ALL_SIGNATURE_BLOB);
41 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_DEBUG_INFO);
42 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_LEGACY_SHADER);
43 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_XNA_PREPASS_SHADER);
44 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_XNA_SHADER);
45 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_ALTERNATE_SHADER);
46 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_COMPILE_DETAILS);
47 WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_COMPILE_PERF);
49 FIXME("Unrecognized D3D_BLOB_PART %#x\n", part);
50 return "unrecognized";
54 const char *debug_print_srcmod(DWORD mod)
58 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_NEG);
59 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_BIAS);
60 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_BIASNEG);
61 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_SIGN);
62 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_SIGNNEG);
63 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_COMP);
64 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_X2);
65 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_X2NEG);
66 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_DZ);
67 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_DW);
68 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_ABS);
69 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_ABSNEG);
70 WINE_D3DCOMPILER_TO_STR(BWRITERSPSM_NOT);
72 FIXME("Unrecognized source modifier %#x.\n", mod);
73 return "unrecognized_src_mod";
77 #undef WINE_D3DCOMPILER_TO_STR
79 const char *debug_print_dstmod(DWORD mod)
85 case BWRITERSPDM_SATURATE:
87 case BWRITERSPDM_PARTIALPRECISION:
89 case BWRITERSPDM_MSAMPCENTROID:
91 case BWRITERSPDM_SATURATE | BWRITERSPDM_PARTIALPRECISION:
93 case BWRITERSPDM_SATURATE | BWRITERSPDM_MSAMPCENTROID:
94 return "_sat_centroid";
95 case BWRITERSPDM_PARTIALPRECISION | BWRITERSPDM_MSAMPCENTROID:
96 return "_pp_centroid";
97 case BWRITERSPDM_SATURATE | BWRITERSPDM_PARTIALPRECISION | BWRITERSPDM_MSAMPCENTROID:
98 return "_sat_pp_centroid";
100 return "Unexpected modifier\n";
104 const char *debug_print_shift(DWORD shift)
106 static const char * const shiftstrings[] =
125 return shiftstrings[shift];
128 static const char *get_regname(const struct shader_reg *reg)
132 case BWRITERSPR_TEMP:
133 return wine_dbg_sprintf("r%u", reg->regnum);
134 case BWRITERSPR_INPUT:
135 return wine_dbg_sprintf("v%u", reg->regnum);
136 case BWRITERSPR_CONST:
137 return wine_dbg_sprintf("c%u", reg->regnum);
138 case BWRITERSPR_ADDR:
139 return wine_dbg_sprintf("a%u", reg->regnum);
140 case BWRITERSPR_TEXTURE:
141 return wine_dbg_sprintf("t%u", reg->regnum);
142 case BWRITERSPR_RASTOUT:
145 case BWRITERSRO_POSITION: return "oPos";
146 case BWRITERSRO_FOG: return "oFog";
147 case BWRITERSRO_POINT_SIZE: return "oPts";
148 default: return "Unexpected RASTOUT";
150 case BWRITERSPR_ATTROUT:
151 return wine_dbg_sprintf("oD%u", reg->regnum);
152 case BWRITERSPR_TEXCRDOUT:
153 return wine_dbg_sprintf("oT%u", reg->regnum);
154 case BWRITERSPR_OUTPUT:
155 return wine_dbg_sprintf("o%u", reg->regnum);
156 case BWRITERSPR_CONSTINT:
157 return wine_dbg_sprintf("i%u", reg->regnum);
158 case BWRITERSPR_COLOROUT:
159 return wine_dbg_sprintf("oC%u", reg->regnum);
160 case BWRITERSPR_DEPTHOUT:
162 case BWRITERSPR_SAMPLER:
163 return wine_dbg_sprintf("s%u", reg->regnum);
164 case BWRITERSPR_CONSTBOOL:
165 return wine_dbg_sprintf("b%u", reg->regnum);
166 case BWRITERSPR_LOOP:
168 case BWRITERSPR_MISCTYPE:
171 case 0: return "vPos";
172 case 1: return "vFace";
173 case 2: return "unexpected misctype";
175 case BWRITERSPR_LABEL:
176 return wine_dbg_sprintf("l%u", reg->regnum);
177 case BWRITERSPR_PREDICATE:
178 return wine_dbg_sprintf("p%u", reg->regnum);
180 return wine_dbg_sprintf("unknown regname %#x", reg->type);
184 static const char *debug_print_writemask(DWORD mask)
187 unsigned char pos = 1;
189 if(mask == BWRITERSP_WRITEMASK_ALL) return "";
191 if(mask & BWRITERSP_WRITEMASK_0) ret[pos++] = 'x';
192 if(mask & BWRITERSP_WRITEMASK_1) ret[pos++] = 'y';
193 if(mask & BWRITERSP_WRITEMASK_2) ret[pos++] = 'z';
194 if(mask & BWRITERSP_WRITEMASK_3) ret[pos++] = 'w';
197 return wine_dbg_sprintf("%s", ret);
200 static const char *debug_print_swizzle(DWORD arg)
208 case BWRITERVS_NOSWIZZLE:
210 case BWRITERVS_SWIZZLE_X:
212 case BWRITERVS_SWIZZLE_Y:
214 case BWRITERVS_SWIZZLE_Z:
216 case BWRITERVS_SWIZZLE_W:
220 swizzle[0] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 0)) & 0x03;
221 swizzle[1] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 2)) & 0x03;
222 swizzle[2] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 4)) & 0x03;
223 swizzle[3] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 6)) & 0x03;
226 for (i = 0; i < 4; ++i)
230 case 0: ret[1 + i] = 'x'; break;
231 case 1: ret[1 + i] = 'y'; break;
232 case 2: ret[1 + i] = 'z'; break;
233 case 3: ret[1 + i] = 'w'; break;
238 return wine_dbg_sprintf("%s", ret);
241 static const char *debug_print_relarg(const struct shader_reg *reg)
243 const char *short_swizzle;
244 if (!reg->rel_reg) return "";
246 short_swizzle = debug_print_swizzle(reg->rel_reg->u.swizzle);
248 if (reg->rel_reg->type == BWRITERSPR_ADDR)
249 return wine_dbg_sprintf("[a%u%s]", reg->rel_reg->regnum, short_swizzle);
250 else if(reg->rel_reg->type == BWRITERSPR_LOOP && reg->rel_reg->regnum == 0)
251 return wine_dbg_sprintf("[aL%s]", short_swizzle);
253 return "Unexpected relative addressing argument";
256 const char *debug_print_dstreg(const struct shader_reg *reg)
258 return wine_dbg_sprintf("%s%s%s", get_regname(reg),
259 debug_print_relarg(reg),
260 debug_print_writemask(reg->u.writemask));
263 const char *debug_print_srcreg(const struct shader_reg *reg)
267 case BWRITERSPSM_NONE:
268 return wine_dbg_sprintf("%s%s%s", get_regname(reg),
269 debug_print_relarg(reg),
270 debug_print_swizzle(reg->u.swizzle));
271 case BWRITERSPSM_NEG:
272 return wine_dbg_sprintf("-%s%s%s", get_regname(reg),
273 debug_print_relarg(reg),
274 debug_print_swizzle(reg->u.swizzle));
275 case BWRITERSPSM_BIAS:
276 return wine_dbg_sprintf("%s%s_bias%s", get_regname(reg),
277 debug_print_relarg(reg),
278 debug_print_swizzle(reg->u.swizzle));
279 case BWRITERSPSM_BIASNEG:
280 return wine_dbg_sprintf("-%s%s_bias%s", get_regname(reg),
281 debug_print_relarg(reg),
282 debug_print_swizzle(reg->u.swizzle));
283 case BWRITERSPSM_SIGN:
284 return wine_dbg_sprintf("%s%s_bx2%s", get_regname(reg),
285 debug_print_relarg(reg),
286 debug_print_swizzle(reg->u.swizzle));
287 case BWRITERSPSM_SIGNNEG:
288 return wine_dbg_sprintf("-%s%s_bx2%s", get_regname(reg),
289 debug_print_relarg(reg),
290 debug_print_swizzle(reg->u.swizzle));
291 case BWRITERSPSM_COMP:
292 return wine_dbg_sprintf("1 - %s%s%s", get_regname(reg),
293 debug_print_relarg(reg),
294 debug_print_swizzle(reg->u.swizzle));
296 return wine_dbg_sprintf("%s%s_x2%s", get_regname(reg),
297 debug_print_relarg(reg),
298 debug_print_swizzle(reg->u.swizzle));
299 case BWRITERSPSM_X2NEG:
300 return wine_dbg_sprintf("-%s%s_x2%s", get_regname(reg),
301 debug_print_relarg(reg),
302 debug_print_swizzle(reg->u.swizzle));
304 return wine_dbg_sprintf("%s%s_dz%s", get_regname(reg),
305 debug_print_relarg(reg),
306 debug_print_swizzle(reg->u.swizzle));
308 return wine_dbg_sprintf("%s%s_dw%s", get_regname(reg),
309 debug_print_relarg(reg),
310 debug_print_swizzle(reg->u.swizzle));
311 case BWRITERSPSM_ABS:
312 return wine_dbg_sprintf("%s%s_abs%s", get_regname(reg),
313 debug_print_relarg(reg),
314 debug_print_swizzle(reg->u.swizzle));
315 case BWRITERSPSM_ABSNEG:
316 return wine_dbg_sprintf("-%s%s_abs%s", get_regname(reg),
317 debug_print_relarg(reg),
318 debug_print_swizzle(reg->u.swizzle));
319 case BWRITERSPSM_NOT:
320 return wine_dbg_sprintf("!%s%s%s", get_regname(reg),
321 debug_print_relarg(reg),
322 debug_print_swizzle(reg->u.swizzle));
324 return "Unknown modifier";
327 const char *debug_print_comp(DWORD comp)
331 case BWRITER_COMPARISON_NONE: return "";
332 case BWRITER_COMPARISON_GT: return "_gt";
333 case BWRITER_COMPARISON_EQ: return "_eq";
334 case BWRITER_COMPARISON_GE: return "_ge";
335 case BWRITER_COMPARISON_LT: return "_lt";
336 case BWRITER_COMPARISON_NE: return "_ne";
337 case BWRITER_COMPARISON_LE: return "_le";
338 default: return "_unknown";
342 const char *debug_print_opcode(DWORD opcode)
346 case BWRITERSIO_NOP: return "nop";
347 case BWRITERSIO_MOV: return "mov";
348 case BWRITERSIO_ADD: return "add";
349 case BWRITERSIO_SUB: return "sub";
350 case BWRITERSIO_MAD: return "mad";
351 case BWRITERSIO_MUL: return "mul";
352 case BWRITERSIO_RCP: return "rcp";
353 case BWRITERSIO_RSQ: return "rsq";
354 case BWRITERSIO_DP3: return "dp3";
355 case BWRITERSIO_DP4: return "dp4";
356 case BWRITERSIO_MIN: return "min";
357 case BWRITERSIO_MAX: return "max";
358 case BWRITERSIO_SLT: return "slt";
359 case BWRITERSIO_SGE: return "sge";
360 case BWRITERSIO_EXP: return "exp";
361 case BWRITERSIO_LOG: return "log";
362 case BWRITERSIO_LIT: return "lit";
363 case BWRITERSIO_DST: return "dst";
364 case BWRITERSIO_LRP: return "lrp";
365 case BWRITERSIO_FRC: return "frc";
366 case BWRITERSIO_M4x4: return "m4x4";
367 case BWRITERSIO_M4x3: return "m4x3";
368 case BWRITERSIO_M3x4: return "m3x4";
369 case BWRITERSIO_M3x3: return "m3x3";
370 case BWRITERSIO_M3x2: return "m3x2";
371 case BWRITERSIO_CALL: return "call";
372 case BWRITERSIO_CALLNZ: return "callnz";
373 case BWRITERSIO_LOOP: return "loop";
374 case BWRITERSIO_RET: return "ret";
375 case BWRITERSIO_ENDLOOP: return "endloop";
376 case BWRITERSIO_LABEL: return "label";
377 case BWRITERSIO_DCL: return "dcl";
378 case BWRITERSIO_POW: return "pow";
379 case BWRITERSIO_CRS: return "crs";
380 case BWRITERSIO_SGN: return "sgn";
381 case BWRITERSIO_ABS: return "abs";
382 case BWRITERSIO_NRM: return "nrm";
383 case BWRITERSIO_SINCOS: return "sincos";
384 case BWRITERSIO_REP: return "rep";
385 case BWRITERSIO_ENDREP: return "endrep";
386 case BWRITERSIO_IF: return "if";
387 case BWRITERSIO_IFC: return "ifc";
388 case BWRITERSIO_ELSE: return "else";
389 case BWRITERSIO_ENDIF: return "endif";
390 case BWRITERSIO_BREAK: return "break";
391 case BWRITERSIO_BREAKC: return "breakc";
392 case BWRITERSIO_MOVA: return "mova";
393 case BWRITERSIO_DEFB: return "defb";
394 case BWRITERSIO_DEFI: return "defi";
395 case BWRITERSIO_TEXCOORD: return "texcoord";
396 case BWRITERSIO_TEXKILL: return "texkill";
397 case BWRITERSIO_TEX: return "tex";
398 case BWRITERSIO_TEXBEM: return "texbem";
399 case BWRITERSIO_TEXBEML: return "texbeml";
400 case BWRITERSIO_TEXREG2AR: return "texreg2ar";
401 case BWRITERSIO_TEXREG2GB: return "texreg2gb";
402 case BWRITERSIO_TEXM3x2PAD: return "texm3x2pad";
403 case BWRITERSIO_TEXM3x2TEX: return "texm3x2tex";
404 case BWRITERSIO_TEXM3x3PAD: return "texm3x3pad";
405 case BWRITERSIO_TEXM3x3TEX: return "texm3x3tex";
406 case BWRITERSIO_TEXM3x3SPEC: return "texm3x3vspec";
407 case BWRITERSIO_TEXM3x3VSPEC: return "texm3x3vspec";
408 case BWRITERSIO_EXPP: return "expp";
409 case BWRITERSIO_LOGP: return "logp";
410 case BWRITERSIO_CND: return "cnd";
411 case BWRITERSIO_DEF: return "def";
412 case BWRITERSIO_TEXREG2RGB: return "texreg2rgb";
413 case BWRITERSIO_TEXDP3TEX: return "texdp3tex";
414 case BWRITERSIO_TEXM3x2DEPTH: return "texm3x2depth";
415 case BWRITERSIO_TEXDP3: return "texdp3";
416 case BWRITERSIO_TEXM3x3: return "texm3x3";
417 case BWRITERSIO_TEXDEPTH: return "texdepth";
418 case BWRITERSIO_CMP: return "cmp";
419 case BWRITERSIO_BEM: return "bem";
420 case BWRITERSIO_DP2ADD: return "dp2add";
421 case BWRITERSIO_DSX: return "dsx";
422 case BWRITERSIO_DSY: return "dsy";
423 case BWRITERSIO_TEXLDD: return "texldd";
424 case BWRITERSIO_SETP: return "setp";
425 case BWRITERSIO_TEXLDL: return "texldl";
426 case BWRITERSIO_BREAKP: return "breakp";
427 case BWRITERSIO_PHASE: return "phase";
429 case BWRITERSIO_TEXLDP: return "texldp";
430 case BWRITERSIO_TEXLDB: return "texldb";
432 default: return "unknown";
436 void skip_dword_unknown(const char **ptr, unsigned int count)
441 FIXME("Skipping %u unknown DWORDs:\n", count);
442 for (i = 0; i < count; ++i)
445 FIXME("\t0x%08x\n", d);
449 void write_dword_unknown(char **ptr, DWORD d)
451 FIXME("Writing unknown DWORD 0x%08x\n", d);
455 HRESULT dxbc_add_section(struct dxbc *dxbc, DWORD tag, const char *data, DWORD data_size)
457 TRACE("dxbc %p, tag %s, size %#x.\n", dxbc, debugstr_an((const char *)&tag, 4), data_size);
459 if (dxbc->count >= dxbc->size)
461 struct dxbc_section *new_sections;
462 DWORD new_size = dxbc->size << 1;
464 new_sections = HeapReAlloc(GetProcessHeap(), 0, dxbc->sections, new_size * sizeof(*dxbc->sections));
467 ERR("Failed to allocate dxbc section memory\n");
468 return E_OUTOFMEMORY;
471 dxbc->sections = new_sections;
472 dxbc->size = new_size;
475 dxbc->sections[dxbc->count].tag = tag;
476 dxbc->sections[dxbc->count].data_size = data_size;
477 dxbc->sections[dxbc->count].data = data;
483 HRESULT dxbc_init(struct dxbc *dxbc, UINT size)
485 TRACE("dxbc %p, size %u.\n", dxbc, size);
487 /* use a good starting value for the size if none specified */
490 dxbc->sections = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*dxbc->sections));
493 ERR("Failed to allocate dxbc section memory\n");
494 return E_OUTOFMEMORY;
503 HRESULT dxbc_parse(const char *data, SIZE_T data_size, struct dxbc *dxbc)
505 const char *ptr = data;
508 DWORD tag, total_size, chunk_count;
512 WARN("No data supplied.\n");
516 read_dword(&ptr, &tag);
517 TRACE("tag: %s.\n", debugstr_an((const char *)&tag, 4));
521 WARN("Wrong tag.\n");
526 skip_dword_unknown(&ptr, 4);
528 skip_dword_unknown(&ptr, 1);
530 read_dword(&ptr, &total_size);
531 TRACE("total size: %#x\n", total_size);
533 if (data_size != total_size)
535 WARN("Wrong size supplied.\n");
536 return D3DERR_INVALIDCALL;
539 read_dword(&ptr, &chunk_count);
540 TRACE("chunk count: %#x\n", chunk_count);
542 hr = dxbc_init(dxbc, chunk_count);
545 WARN("Failed to init dxbc\n");
549 for (i = 0; i < chunk_count; ++i)
551 DWORD chunk_tag, chunk_size;
552 const char *chunk_ptr;
555 read_dword(&ptr, &chunk_offset);
556 TRACE("chunk %u at offset %#x\n", i, chunk_offset);
558 chunk_ptr = data + chunk_offset;
560 read_dword(&chunk_ptr, &chunk_tag);
561 read_dword(&chunk_ptr, &chunk_size);
563 hr = dxbc_add_section(dxbc, chunk_tag, chunk_ptr, chunk_size);
566 WARN("Failed to add section to dxbc\n");
574 void dxbc_destroy(struct dxbc *dxbc)
576 TRACE("dxbc %p.\n", dxbc);
578 HeapFree(GetProcessHeap(), 0, dxbc->sections);
581 HRESULT dxbc_write_blob(struct dxbc *dxbc, ID3DBlob **blob)
583 DWORD size = 32, offset = size + 4 * dxbc->count;
589 TRACE("dxbc %p, blob %p.\n", dxbc, blob);
591 for (i = 0; i < dxbc->count; ++i)
593 size += 12 + dxbc->sections[i].data_size;
596 hr = D3DCreateBlob(size, &object);
599 WARN("Failed to create blob\n");
603 ptr = ID3D10Blob_GetBufferPointer(object);
605 write_dword(&ptr, TAG_DXBC);
608 write_dword_unknown(&ptr, 0);
609 write_dword_unknown(&ptr, 0);
610 write_dword_unknown(&ptr, 0);
611 write_dword_unknown(&ptr, 0);
613 /* seems to be always 1 */
614 write_dword_unknown(&ptr, 1);
617 write_dword(&ptr, size);
620 write_dword(&ptr, dxbc->count);
622 /* write the chunk offsets */
623 for (i = 0; i < dxbc->count; ++i)
625 write_dword(&ptr, offset);
626 offset += 8 + dxbc->sections[i].data_size;
629 /* write the chunks */
630 for (i = 0; i < dxbc->count; ++i)
632 write_dword(&ptr, dxbc->sections[i].tag);
633 write_dword(&ptr, dxbc->sections[i].data_size);
634 memcpy(ptr, dxbc->sections[i].data, dxbc->sections[i].data_size);
635 ptr += dxbc->sections[i].data_size;
638 TRACE("Created ID3DBlob %p\n", object);