VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/shaderlib/shader.c@ 82700

Last change on this file since 82700 was 82693, checked in by vboxsync, 5 years ago

3D: Sampler index validation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.4 KB
Line 
1/*
2 * Copyright 2002-2003 Jason Edmeades
3 * Copyright 2002-2003 Raphael Junqueira
4 * Copyright 2004 Christian Costa
5 * Copyright 2005 Oliver Stieber
6 * Copyright 2006 Ivan Gyurdiev
7 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8 * Copyright 2009 Henri Verbeet for CodeWeavers
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25/*
26 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
27 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
28 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
29 * a choice of LGPL license versions is made available with the language indicating
30 * that LGPLv2 or any later version may be used, or where a choice of which version
31 * of the LGPL is applied is otherwise unspecified.
32 */
33
34#include "config.h"
35#include "wine/port.h"
36
37#include <math.h>
38#include <stdio.h>
39#include <string.h>
40
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
44WINE_DECLARE_DEBUG_CHANNEL(d3d);
45
46static const char *shader_opcode_names[] =
47{
48 /* WINED3DSIH_ABS */ "abs",
49 /* WINED3DSIH_ADD */ "add",
50 /* WINED3DSIH_BEM */ "bem",
51 /* WINED3DSIH_BREAK */ "break",
52 /* WINED3DSIH_BREAKC */ "breakc",
53 /* WINED3DSIH_BREAKP */ "breakp",
54 /* WINED3DSIH_CALL */ "call",
55 /* WINED3DSIH_CALLNZ */ "callnz",
56 /* WINED3DSIH_CMP */ "cmp",
57 /* WINED3DSIH_CND */ "cnd",
58 /* WINED3DSIH_CRS */ "crs",
59 /* WINED3DSIH_CUT */ "cut",
60 /* WINED3DSIH_DCL */ "dcl",
61 /* WINED3DSIH_DEF */ "def",
62 /* WINED3DSIH_DEFB */ "defb",
63 /* WINED3DSIH_DEFI */ "defi",
64 /* WINED3DSIH_DP2ADD */ "dp2add",
65 /* WINED3DSIH_DP3 */ "dp3",
66 /* WINED3DSIH_DP4 */ "dp4",
67 /* WINED3DSIH_DST */ "dst",
68 /* WINED3DSIH_DSX */ "dsx",
69 /* WINED3DSIH_DSY */ "dsy",
70 /* WINED3DSIH_ELSE */ "else",
71 /* WINED3DSIH_EMIT */ "emit",
72 /* WINED3DSIH_ENDIF */ "endif",
73 /* WINED3DSIH_ENDLOOP */ "endloop",
74 /* WINED3DSIH_ENDREP */ "endrep",
75 /* WINED3DSIH_EXP */ "exp",
76 /* WINED3DSIH_EXPP */ "expp",
77 /* WINED3DSIH_FRC */ "frc",
78 /* WINED3DSIH_IADD */ "iadd",
79 /* WINED3DSIH_IF */ "if",
80 /* WINED3DSIH_IFC */ "ifc",
81 /* WINED3DSIH_IGE */ "ige",
82 /* WINED3DSIH_LABEL */ "label",
83 /* WINED3DSIH_LIT */ "lit",
84 /* WINED3DSIH_LOG */ "log",
85 /* WINED3DSIH_LOGP */ "logp",
86 /* WINED3DSIH_LOOP */ "loop",
87 /* WINED3DSIH_LRP */ "lrp",
88 /* WINED3DSIH_LT */ "lt",
89 /* WINED3DSIH_M3x2 */ "m3x2",
90 /* WINED3DSIH_M3x3 */ "m3x3",
91 /* WINED3DSIH_M3x4 */ "m3x4",
92 /* WINED3DSIH_M4x3 */ "m4x3",
93 /* WINED3DSIH_M4x4 */ "m4x4",
94 /* WINED3DSIH_MAD */ "mad",
95 /* WINED3DSIH_MAX */ "max",
96 /* WINED3DSIH_MIN */ "min",
97 /* WINED3DSIH_MOV */ "mov",
98 /* WINED3DSIH_MOVA */ "mova",
99 /* WINED3DSIH_MUL */ "mul",
100 /* WINED3DSIH_NOP */ "nop",
101 /* WINED3DSIH_NRM */ "nrm",
102 /* WINED3DSIH_PHASE */ "phase",
103 /* WINED3DSIH_POW */ "pow",
104 /* WINED3DSIH_RCP */ "rcp",
105 /* WINED3DSIH_REP */ "rep",
106 /* WINED3DSIH_RET */ "ret",
107 /* WINED3DSIH_RSQ */ "rsq",
108 /* WINED3DSIH_SETP */ "setp",
109 /* WINED3DSIH_SGE */ "sge",
110 /* WINED3DSIH_SGN */ "sgn",
111 /* WINED3DSIH_SINCOS */ "sincos",
112 /* WINED3DSIH_SLT */ "slt",
113 /* WINED3DSIH_SUB */ "sub",
114 /* WINED3DSIH_TEX */ "texld",
115 /* WINED3DSIH_TEXBEM */ "texbem",
116 /* WINED3DSIH_TEXBEML */ "texbeml",
117 /* WINED3DSIH_TEXCOORD */ "texcrd",
118 /* WINED3DSIH_TEXDEPTH */ "texdepth",
119 /* WINED3DSIH_TEXDP3 */ "texdp3",
120 /* WINED3DSIH_TEXDP3TEX */ "texdp3tex",
121 /* WINED3DSIH_TEXKILL */ "texkill",
122 /* WINED3DSIH_TEXLDD */ "texldd",
123 /* WINED3DSIH_TEXLDL */ "texldl",
124 /* WINED3DSIH_TEXM3x2DEPTH */ "texm3x2depth",
125 /* WINED3DSIH_TEXM3x2PAD */ "texm3x2pad",
126 /* WINED3DSIH_TEXM3x2TEX */ "texm3x2tex",
127 /* WINED3DSIH_TEXM3x3 */ "texm3x3",
128 /* WINED3DSIH_TEXM3x3DIFF */ "texm3x3diff",
129 /* WINED3DSIH_TEXM3x3PAD */ "texm3x3pad",
130 /* WINED3DSIH_TEXM3x3SPEC */ "texm3x3spec",
131 /* WINED3DSIH_TEXM3x3TEX */ "texm3x3tex",
132 /* WINED3DSIH_TEXM3x3VSPEC */ "texm3x3vspec",
133 /* WINED3DSIH_TEXREG2AR */ "texreg2ar",
134 /* WINED3DSIH_TEXREG2GB */ "texreg2gb",
135 /* WINED3DSIH_TEXREG2RGB */ "texreg2rgb",
136};
137
138static const char *semantic_names[] =
139{
140 /* WINED3DDECLUSAGE_POSITION */ "SV_POSITION",
141 /* WINED3DDECLUSAGE_BLENDWEIGHT */ "BLENDWEIGHT",
142 /* WINED3DDECLUSAGE_BLENDINDICES */ "BLENDINDICES",
143 /* WINED3DDECLUSAGE_NORMAL */ "NORMAL",
144 /* WINED3DDECLUSAGE_PSIZE */ "PSIZE",
145 /* WINED3DDECLUSAGE_TEXCOORD */ "TEXCOORD",
146 /* WINED3DDECLUSAGE_TANGENT */ "TANGENT",
147 /* WINED3DDECLUSAGE_BINORMAL */ "BINORMAL",
148 /* WINED3DDECLUSAGE_TESSFACTOR */ "TESSFACTOR",
149 /* WINED3DDECLUSAGE_POSITIONT */ "POSITIONT",
150 /* WINED3DDECLUSAGE_COLOR */ "COLOR",
151 /* WINED3DDECLUSAGE_FOG */ "FOG",
152 /* WINED3DDECLUSAGE_DEPTH */ "DEPTH",
153 /* WINED3DDECLUSAGE_SAMPLE */ "SAMPLE",
154};
155
156static const char *shader_semantic_name_from_usage(WINED3DDECLUSAGE usage)
157{
158 if (usage >= sizeof(semantic_names) / sizeof(*semantic_names))
159 {
160 FIXME("Unrecognized usage %#x.\n", usage);
161 return "UNRECOGNIZED";
162 }
163
164 return semantic_names[usage];
165}
166
167static WINED3DDECLUSAGE shader_usage_from_semantic_name(const char *name)
168{
169 unsigned int i;
170
171 for (i = 0; i < sizeof(semantic_names) / sizeof(*semantic_names); ++i)
172 {
173 if (!strcmp(name, semantic_names[i])) return i;
174 }
175
176 return ~0U;
177}
178
179BOOL shader_match_semantic(const char *semantic_name, WINED3DDECLUSAGE usage)
180{
181 return !strcmp(semantic_name, shader_semantic_name_from_usage(usage));
182}
183
184static void shader_signature_from_semantic(struct wined3d_shader_signature_element *e,
185 const struct wined3d_shader_semantic *s)
186{
187 e->semantic_name = shader_semantic_name_from_usage(s->usage);
188 e->semantic_idx = s->usage_idx;
189 e->sysval_semantic = 0;
190 e->component_type = 0;
191 e->register_idx = s->reg.reg.idx;
192 e->mask = s->reg.write_mask;
193}
194
195static const struct wined3d_shader_frontend *shader_select_frontend(DWORD version_token)
196{
197 switch (version_token >> 16)
198 {
199 case WINED3D_SM1_VS:
200 case WINED3D_SM1_PS:
201 return &sm1_shader_frontend;
202
203 case WINED3D_SM4_PS:
204 case WINED3D_SM4_VS:
205 case WINED3D_SM4_GS:
206 return &sm4_shader_frontend;
207
208 default:
209 FIXME("Unrecognised version token %#x\n", version_token);
210 return NULL;
211 }
212}
213
214void shader_buffer_clear(struct wined3d_shader_buffer *buffer)
215{
216 buffer->buffer[0] = '\0';
217 buffer->bsize = 0;
218 buffer->lineNo = 0;
219 buffer->newline = TRUE;
220}
221
222BOOL shader_buffer_init(struct wined3d_shader_buffer *buffer)
223{
224 buffer->buffer = HeapAlloc(GetProcessHeap(), 0, SHADER_PGMSIZE);
225 if (!buffer->buffer)
226 {
227 ERR("Failed to allocate shader buffer memory.\n");
228 return FALSE;
229 }
230
231 shader_buffer_clear(buffer);
232 return TRUE;
233}
234
235void shader_buffer_free(struct wined3d_shader_buffer *buffer)
236{
237 HeapFree(GetProcessHeap(), 0, buffer->buffer);
238}
239
240int shader_vaddline(struct wined3d_shader_buffer *buffer, const char *format, va_list args)
241{
242 char *base = buffer->buffer + buffer->bsize;
243 int rc;
244
245 rc = vsnprintf(base, SHADER_PGMSIZE - 1 - buffer->bsize, format, args);
246
247 if (rc < 0 /* C89 */ || (unsigned int)rc > SHADER_PGMSIZE - 1 - buffer->bsize /* C99 */)
248 {
249 ERR("The buffer allocated for the shader program string "
250 "is too small at %d bytes.\n", SHADER_PGMSIZE);
251 buffer->bsize = SHADER_PGMSIZE - 1;
252 return -1;
253 }
254
255 if (buffer->newline)
256 {
257 TRACE("GL HW (%u, %u) : %s", buffer->lineNo + 1, buffer->bsize, base);
258 buffer->newline = FALSE;
259 }
260 else
261 {
262 TRACE("%s", base);
263 }
264
265 buffer->bsize += rc;
266 if (buffer->buffer[buffer->bsize-1] == '\n')
267 {
268 ++buffer->lineNo;
269 buffer->newline = TRUE;
270 }
271
272 return 0;
273}
274
275int shader_addline(struct wined3d_shader_buffer *buffer, const char *format, ...)
276{
277 va_list args;
278 int ret;
279
280 va_start(args, format);
281 ret = shader_vaddline(buffer, format, args);
282 va_end(args);
283
284 return ret;
285}
286
287static void shader_init(struct IWineD3DBaseShaderClass *shader, IWineD3DDeviceImpl *device,
288 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
289{
290 shader->ref = 1;
291 shader->device = (IWineD3DDevice *)device;
292 shader->parent = parent;
293 shader->parent_ops = parent_ops;
294 list_init(&shader->linked_programs);
295 list_add_head(&device->shaders, &shader->shader_list_entry);
296}
297
298/* Convert floating point offset relative to a register file to an absolute
299 * offset for float constants. */
300static unsigned int shader_get_float_offset(WINED3DSHADER_PARAM_REGISTER_TYPE register_type, UINT register_idx)
301{
302 switch (register_type)
303 {
304 case WINED3DSPR_CONST: return register_idx;
305 case WINED3DSPR_CONST2: return 2048 + register_idx;
306 case WINED3DSPR_CONST3: return 4096 + register_idx;
307 case WINED3DSPR_CONST4: return 6144 + register_idx;
308 default:
309 FIXME("Unsupported register type: %u.\n", register_type);
310 return register_idx;
311 }
312}
313
314static void shader_delete_constant_list(struct list *clist)
315{
316 struct local_constant *constant;
317 struct list *ptr;
318
319 ptr = list_head(clist);
320 while (ptr)
321 {
322 constant = LIST_ENTRY(ptr, struct local_constant, entry);
323 ptr = list_next(clist, ptr);
324 HeapFree(GetProcessHeap(), 0, constant);
325 }
326 list_init(clist);
327}
328
329static inline void set_bitmap_bit(DWORD *bitmap, DWORD bit)
330{
331 DWORD idx, shift;
332 idx = bit >> 5;
333 shift = bit & 0x1f;
334 bitmap[idx] |= (1 << shift);
335}
336
337static HRESULT shader_record_register_usage(IWineD3DBaseShaderImpl *shader, struct shader_reg_maps *reg_maps,
338 const struct wined3d_shader_register *reg, enum wined3d_shader_type shader_type)
339{
340 switch (reg->type)
341 {
342 case WINED3DSPR_TEXTURE: /* WINED3DSPR_ADDR */
343 if (shader_type == WINED3D_SHADER_TYPE_PIXEL) reg_maps->texcoord |= 1 << reg->idx;
344 else reg_maps->address |= 1 << reg->idx;
345 break;
346
347 case WINED3DSPR_TEMP:
348 reg_maps->temporary |= 1 << reg->idx;
349 break;
350
351 case WINED3DSPR_INPUT:
352 if (shader_type == WINED3D_SHADER_TYPE_PIXEL)
353 {
354 if (reg->rel_addr)
355 {
356 /* If relative addressing is used, we must assume that all registers
357 * are used. Even if it is a construct like v3[aL], we can't assume
358 * that v0, v1 and v2 aren't read because aL can be negative */
359 unsigned int i;
360 for (i = 0; i < MAX_REG_INPUT; ++i)
361 {
362 ((IWineD3DPixelShaderImpl *)shader)->input_reg_used[i] = TRUE;
363 }
364 }
365 else
366 {
367 unsigned int reg_idx = reg->idx;
368 AssertReturn(reg_idx < MAX_REG_INPUT, E_INVALIDARG);
369
370 ((IWineD3DPixelShaderImpl *)shader)->input_reg_used[reg_idx] = TRUE;
371 }
372 }
373 else reg_maps->input_registers |= 1 << reg->idx;
374 break;
375
376 case WINED3DSPR_RASTOUT:
377 if (reg->idx == 1) reg_maps->fog = 1;
378 break;
379
380 case WINED3DSPR_MISCTYPE:
381 if (shader_type == WINED3D_SHADER_TYPE_PIXEL)
382 {
383 if (reg->idx == 0) reg_maps->vpos = 1;
384 else if (reg->idx == 1) reg_maps->usesfacing = 1;
385 }
386 break;
387
388 case WINED3DSPR_CONST:
389 if (reg->rel_addr)
390 {
391 if (shader_type != WINED3D_SHADER_TYPE_PIXEL)
392 {
393 if (reg->idx < ((IWineD3DVertexShaderImpl *)shader)->min_rel_offset)
394 {
395 ((IWineD3DVertexShaderImpl *)shader)->min_rel_offset = reg->idx;
396 }
397 if (reg->idx > ((IWineD3DVertexShaderImpl *)shader)->max_rel_offset)
398 {
399 ((IWineD3DVertexShaderImpl *)shader)->max_rel_offset = reg->idx;
400 }
401 }
402 reg_maps->usesrelconstF = TRUE;
403 }
404 else
405 {
406 set_bitmap_bit(reg_maps->constf, reg->idx);
407 }
408 break;
409
410 case WINED3DSPR_CONSTINT:
411 reg_maps->integer_constants |= (1 << reg->idx);
412 break;
413
414 case WINED3DSPR_CONSTBOOL:
415 reg_maps->boolean_constants |= (1 << reg->idx);
416 break;
417
418 case WINED3DSPR_COLOROUT:
419 reg_maps->highest_render_target = max(reg_maps->highest_render_target, reg->idx);
420 break;
421
422 default:
423 TRACE("Not recording register of type %#x and idx %u\n", reg->type, reg->idx);
424 break;
425 }
426
427 return S_OK;
428}
429
430static unsigned int get_instr_extra_regcount(enum WINED3D_SHADER_INSTRUCTION_HANDLER instr, unsigned int param)
431{
432 switch (instr)
433 {
434 case WINED3DSIH_M4x4:
435 case WINED3DSIH_M3x4:
436 return param == 1 ? 3 : 0;
437
438 case WINED3DSIH_M4x3:
439 case WINED3DSIH_M3x3:
440 return param == 1 ? 2 : 0;
441
442 case WINED3DSIH_M3x2:
443 return param == 1 ? 1 : 0;
444
445 default:
446 return 0;
447 }
448}
449
450/* Note that this does not count the loop register as an address register. */
451static HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3d_shader_frontend *fe,
452 struct shader_reg_maps *reg_maps, struct wined3d_shader_signature_element *input_signature,
453 struct wined3d_shader_signature_element *output_signature, const DWORD *byte_code, DWORD constf_size)
454{
455 IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)iface;
456 unsigned int cur_loop_depth = 0, max_loop_depth = 0;
457 void *fe_data = shader->baseShader.frontend_data;
458 struct wined3d_shader_version shader_version;
459 const DWORD *ptr = byte_code;
460
461 memset(reg_maps, 0, sizeof(*reg_maps));
462
463 /* get_registers_used() is called on every compile on some 1.x shaders,
464 * which can result in stacking up a collection of local constants.
465 * Delete the old constants if existing. */
466 shader_delete_constant_list(&shader->baseShader.constantsF);
467 shader_delete_constant_list(&shader->baseShader.constantsB);
468 shader_delete_constant_list(&shader->baseShader.constantsI);
469
470 fe->shader_read_header(fe_data, &ptr, &shader_version);
471 reg_maps->shader_version = shader_version;
472
473 reg_maps->constf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
474 sizeof(*reg_maps->constf) * ((constf_size + 31) / 32));
475 if (!reg_maps->constf)
476 {
477 ERR("Failed to allocate constant map memory.\n");
478 return E_OUTOFMEMORY;
479 }
480
481 while (!fe->shader_is_end(fe_data, &ptr))
482 {
483 struct wined3d_shader_instruction ins;
484 const char *comment;
485 UINT comment_size;
486 UINT param_size;
487
488 /* Skip comments. */
489 fe->shader_read_comment(&ptr, &comment, &comment_size);
490 if (comment) continue;
491
492 /* Fetch opcode. */
493 fe->shader_read_opcode(fe_data, &ptr, &ins, &param_size);
494
495 /* Unhandled opcode, and its parameters. */
496 if (ins.handler_idx == WINED3DSIH_TABLE_SIZE)
497 {
498 TRACE("Skipping unrecognized instruction.\n");
499 ptr += param_size;
500 continue;
501 }
502
503 /* Handle declarations. */
504 if (ins.handler_idx == WINED3DSIH_DCL)
505 {
506 struct wined3d_shader_semantic semantic;
507 unsigned int reg_idx;
508
509 fe->shader_read_semantic(&ptr, &semantic);
510 reg_idx = semantic.reg.reg.idx;
511
512 switch (semantic.reg.reg.type)
513 {
514 /* Mark input registers used. */
515 case WINED3DSPR_INPUT:
516 AssertReturn(reg_idx < max(MAX_ATTRIBS, MAX_REG_INPUT), E_INVALIDARG);
517 reg_maps->input_registers |= 1 << reg_idx;
518 shader_signature_from_semantic(&input_signature[reg_idx], &semantic);
519 break;
520
521 /* Vertex shader: mark 3.0 output registers used, save token. */
522 case WINED3DSPR_OUTPUT:
523 AssertReturn(reg_idx < MAX_REG_OUTPUT, E_INVALIDARG);
524 reg_maps->output_registers |= 1 << reg_idx;
525 shader_signature_from_semantic(&output_signature[reg_idx], &semantic);
526 if (semantic.usage == WINED3DDECLUSAGE_FOG) reg_maps->fog = 1;
527 break;
528
529 /* Save sampler usage token. */
530 case WINED3DSPR_SAMPLER:
531 AssertReturn(reg_idx < RT_ELEMENTS(reg_maps->sampler_type), E_INVALIDARG);
532 reg_maps->sampler_type[reg_idx] = semantic.sampler_type;
533 break;
534
535 default:
536 TRACE("Not recording DCL register type %#x.\n", semantic.reg.reg.type);
537 break;
538 }
539 }
540 else if (ins.handler_idx == WINED3DSIH_DEF)
541 {
542 struct wined3d_shader_src_param rel_addr;
543 struct wined3d_shader_dst_param dst;
544 local_constant* lconst;
545
546 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
547
548 AssertReturn(dst.reg.idx < constf_size, E_INVALIDARG);
549
550 lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
551 if (!lconst) return E_OUTOFMEMORY;
552
553 lconst->idx = dst.reg.idx;
554 memcpy(lconst->value, ptr, 4 * sizeof(DWORD));
555 ptr += 4;
556
557 /* In pixel shader 1.X shaders, the constants are clamped between [-1;1] */
558 if (shader_version.major == 1 && shader_version.type == WINED3D_SHADER_TYPE_PIXEL)
559 {
560 float *value = (float *)lconst->value;
561 if (value[0] < -1.0f) value[0] = -1.0f;
562 else if (value[0] > 1.0f) value[0] = 1.0f;
563 if (value[1] < -1.0f) value[1] = -1.0f;
564 else if (value[1] > 1.0f) value[1] = 1.0f;
565 if (value[2] < -1.0f) value[2] = -1.0f;
566 else if (value[2] > 1.0f) value[2] = 1.0f;
567 if (value[3] < -1.0f) value[3] = -1.0f;
568 else if (value[3] > 1.0f) value[3] = 1.0f;
569 }
570
571 list_add_head(&shader->baseShader.constantsF, &lconst->entry);
572 }
573 else if (ins.handler_idx == WINED3DSIH_DEFI)
574 {
575 struct wined3d_shader_src_param rel_addr;
576 struct wined3d_shader_dst_param dst;
577 local_constant* lconst;
578
579 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
580
581 AssertReturn(dst.reg.idx < MAX_CONST_I, E_INVALIDARG);
582
583 lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
584 if (!lconst) return E_OUTOFMEMORY;
585
586 lconst->idx = dst.reg.idx;
587 memcpy(lconst->value, ptr, 4 * sizeof(DWORD));
588 ptr += 4;
589
590 list_add_head(&shader->baseShader.constantsI, &lconst->entry);
591 reg_maps->local_int_consts |= (1 << dst.reg.idx);
592 }
593 else if (ins.handler_idx == WINED3DSIH_DEFB)
594 {
595 struct wined3d_shader_src_param rel_addr;
596 struct wined3d_shader_dst_param dst;
597 local_constant* lconst;
598
599 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
600
601 AssertReturn(dst.reg.idx < MAX_CONST_B, E_INVALIDARG);
602
603 lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
604 if (!lconst) return E_OUTOFMEMORY;
605
606 lconst->idx = dst.reg.idx;
607 memcpy(lconst->value, ptr, sizeof(DWORD));
608 ++ptr;
609
610 list_add_head(&shader->baseShader.constantsB, &lconst->entry);
611 reg_maps->local_bool_consts |= (1 << dst.reg.idx);
612 }
613 /* If there's a loop in the shader. */
614 else if (ins.handler_idx == WINED3DSIH_LOOP
615 || ins.handler_idx == WINED3DSIH_REP)
616 {
617 struct wined3d_shader_src_param src, rel_addr;
618
619 fe->shader_read_src_param(fe_data, &ptr, &src, &rel_addr);
620
621 /* Rep and Loop always use an integer constant for the control parameters. */
622 if (ins.handler_idx == WINED3DSIH_REP)
623 {
624 reg_maps->integer_constants |= 1 << src.reg.idx;
625 }
626 else
627 {
628 fe->shader_read_src_param(fe_data, &ptr, &src, &rel_addr);
629 reg_maps->integer_constants |= 1 << src.reg.idx;
630 }
631
632 cur_loop_depth++;
633 if (cur_loop_depth > max_loop_depth) max_loop_depth = cur_loop_depth;
634 }
635 else if (ins.handler_idx == WINED3DSIH_ENDLOOP
636 || ins.handler_idx == WINED3DSIH_ENDREP)
637 {
638 cur_loop_depth--;
639 }
640 /* For subroutine prototypes. */
641 else if (ins.handler_idx == WINED3DSIH_LABEL)
642 {
643 struct wined3d_shader_src_param src, rel_addr;
644
645 fe->shader_read_src_param(fe_data, &ptr, &src, &rel_addr);
646 reg_maps->labels |= 1 << src.reg.idx;
647 }
648 /* Set texture, address, temporary registers. */
649 else
650 {
651 BOOL color0_mov = FALSE;
652 int i, limit;
653
654 /* This will loop over all the registers and try to
655 * make a bitmask of the ones we're interested in.
656 *
657 * Relative addressing tokens are ignored, but that's
658 * okay, since we'll catch any address registers when
659 * they are initialized (required by spec). */
660 if (ins.dst_count)
661 {
662 struct wined3d_shader_src_param dst_rel_addr;
663 struct wined3d_shader_dst_param dst_param;
664 HRESULT hr;
665
666 fe->shader_read_dst_param(fe_data, &ptr, &dst_param, &dst_rel_addr);
667
668 hr = shader_record_register_usage(shader, reg_maps, &dst_param.reg, shader_version.type);
669 if (FAILED(hr))
670 {
671 ERR("shader_record_register_usage failed.\n");
672 return hr;
673 }
674
675 /* WINED3DSPR_TEXCRDOUT is the same as WINED3DSPR_OUTPUT. _OUTPUT can be > MAX_REG_TEXCRD and
676 * is used in >= 3.0 shaders. Filter 3.0 shaders to prevent overflows, and also filter pixel
677 * shaders because TECRDOUT isn't used in them, but future register types might cause issues */
678 if (shader_version.type == WINED3D_SHADER_TYPE_VERTEX && shader_version.major < 3
679 && dst_param.reg.type == WINED3DSPR_TEXCRDOUT)
680 {
681 unsigned int idx = dst_param.reg.idx;
682
683 if (idx >= MAX_REG_TEXCRD)
684 {
685 ERR("Invalid texcoord index %d.\n", idx);
686 return E_INVALIDARG;
687 }
688
689 reg_maps->texcoord_mask[idx] |= dst_param.write_mask;
690 }
691
692 if (shader_version.type == WINED3D_SHADER_TYPE_PIXEL)
693 {
694 IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *)shader;
695
696 if (dst_param.reg.type == WINED3DSPR_COLOROUT && dst_param.reg.idx == 0)
697 {
698 /* Many 2.0 and 3.0 pixel shaders end with a MOV from a temp register to
699 * COLOROUT 0. If we know this in advance, the ARB shader backend can skip
700 * the mov and perform the sRGB write correction from the source register.
701 *
702 * However, if the mov is only partial, we can't do this, and if the write
703 * comes from an instruction other than MOV it is hard to do as well. If
704 * COLOROUT 0 is overwritten partially later, the marker is dropped again. */
705
706 ps->color0_mov = FALSE;
707 if (ins.handler_idx == WINED3DSIH_MOV)
708 {
709 /* Used later when the source register is read. */
710 color0_mov = TRUE;
711 }
712 }
713 /* Also drop the MOV marker if the source register is overwritten prior to the shader
714 * end
715 */
716 else if (dst_param.reg.type == WINED3DSPR_TEMP && dst_param.reg.idx == ps->color0_reg)
717 {
718 ps->color0_mov = FALSE;
719 }
720 }
721
722 /* Declare 1.x samplers implicitly, based on the destination reg. number. */
723 if (ins.handler_idx == WINED3DSIH_TEX
724 || ins.handler_idx == WINED3DSIH_TEXBEM
725 || ins.handler_idx == WINED3DSIH_TEXBEML
726 || ins.handler_idx == WINED3DSIH_TEXDP3TEX
727 || ins.handler_idx == WINED3DSIH_TEXM3x2TEX
728 || ins.handler_idx == WINED3DSIH_TEXM3x3SPEC
729 || ins.handler_idx == WINED3DSIH_TEXM3x3TEX
730 || ins.handler_idx == WINED3DSIH_TEXM3x3VSPEC
731 || ins.handler_idx == WINED3DSIH_TEXREG2AR
732 || ins.handler_idx == WINED3DSIH_TEXREG2GB
733 || ins.handler_idx == WINED3DSIH_TEXREG2RGB)
734 {
735 unsigned int sampler_idx;
736 AssertReturn(shader_version.major == 1, E_INVALIDARG);
737
738 /* Fake sampler usage, only set reserved bit and type. */
739 sampler_idx = dst_param.reg.idx;
740 AssertReturn(sampler_idx < RT_ELEMENTS(reg_maps->sampler_type), E_INVALIDARG);
741
742 TRACE("Setting fake 2D sampler for 1.x pixelshader.\n");
743 reg_maps->sampler_type[sampler_idx] = WINED3DSTT_2D;
744
745 /* texbem is only valid with < 1.4 pixel shaders */
746 if (ins.handler_idx == WINED3DSIH_TEXBEM
747 || ins.handler_idx == WINED3DSIH_TEXBEML)
748 {
749 reg_maps->bumpmat |= 1 << sampler_idx;
750 if (ins.handler_idx == WINED3DSIH_TEXBEML)
751 {
752 reg_maps->luminanceparams |= 1 << sampler_idx;
753 }
754 }
755 }
756 else if (ins.handler_idx == WINED3DSIH_BEM)
757 {
758 unsigned int sampler_idx = dst_param.reg.idx;
759 AssertReturn(shader_version.major == 1, E_INVALIDARG);
760 AssertReturn(sampler_idx < RT_ELEMENTS(reg_maps->sampler_type), E_INVALIDARG);
761
762 reg_maps->bumpmat |= 1 << sampler_idx;
763 }
764 }
765
766 if (ins.handler_idx == WINED3DSIH_NRM) reg_maps->usesnrm = 1;
767 else if (ins.handler_idx == WINED3DSIH_DSY) reg_maps->usesdsy = 1;
768 else if (ins.handler_idx == WINED3DSIH_DSX) reg_maps->usesdsx = 1;
769 else if (ins.handler_idx == WINED3DSIH_TEXLDD) reg_maps->usestexldd = 1;
770 else if (ins.handler_idx == WINED3DSIH_TEXLDL) reg_maps->usestexldl = 1;
771 else if (ins.handler_idx == WINED3DSIH_MOVA) reg_maps->usesmova = 1;
772 else if (ins.handler_idx == WINED3DSIH_IFC) reg_maps->usesifc = 1;
773 else if (ins.handler_idx == WINED3DSIH_CALL) reg_maps->usescall = 1;
774
775 limit = ins.src_count + (ins.predicate ? 1 : 0);
776 for (i = 0; i < limit; ++i)
777 {
778 struct wined3d_shader_src_param src_param, src_rel_addr;
779 unsigned int count;
780
781 fe->shader_read_src_param(fe_data, &ptr, &src_param, &src_rel_addr);
782 count = get_instr_extra_regcount(ins.handler_idx, i);
783
784 shader_record_register_usage(shader, reg_maps, &src_param.reg, shader_version.type);
785 while (count)
786 {
787 ++src_param.reg.idx;
788 shader_record_register_usage(shader, reg_maps, &src_param.reg, shader_version.type);
789 --count;
790 }
791
792 if (color0_mov)
793 {
794 IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *)shader;
795 if (src_param.reg.type == WINED3DSPR_TEMP
796 && src_param.swizzle == WINED3DSP_NOSWIZZLE)
797 {
798 ps->color0_mov = TRUE;
799 ps->color0_reg = src_param.reg.idx;
800 }
801 }
802 }
803 }
804 }
805 reg_maps->loop_depth = max_loop_depth;
806
807 shader->baseShader.functionLength = ((const char *)ptr - (const char *)byte_code);
808
809 return WINED3D_OK;
810}
811
812unsigned int shader_find_free_input_register(const struct shader_reg_maps *reg_maps, unsigned int max)
813{
814 DWORD map = 1 << max;
815 map |= map - 1;
816 map &= reg_maps->shader_version.major < 3 ? ~reg_maps->texcoord : ~reg_maps->input_registers;
817
818 return wined3d_log2i(map);
819}
820
821static void shader_dump_decl_usage(const struct wined3d_shader_semantic *semantic,
822 const struct wined3d_shader_version *shader_version)
823{
824 TRACE("dcl");
825
826 if (semantic->reg.reg.type == WINED3DSPR_SAMPLER)
827 {
828 switch (semantic->sampler_type)
829 {
830 case WINED3DSTT_2D: TRACE("_2d"); break;
831 case WINED3DSTT_CUBE: TRACE("_cube"); break;
832 case WINED3DSTT_VOLUME: TRACE("_volume"); break;
833 default: TRACE("_unknown_ttype(0x%08x)", semantic->sampler_type);
834 }
835 }
836 else
837 {
838 /* Pixel shaders 3.0 don't have usage semantics. */
839 if (shader_version->major < 3 && shader_version->type == WINED3D_SHADER_TYPE_PIXEL) return;
840 else TRACE("_");
841
842 switch (semantic->usage)
843 {
844 case WINED3DDECLUSAGE_POSITION:
845 TRACE("position%u", semantic->usage_idx);
846 break;
847
848 case WINED3DDECLUSAGE_BLENDINDICES:
849 TRACE("blend");
850 break;
851
852 case WINED3DDECLUSAGE_BLENDWEIGHT:
853 TRACE("weight");
854 break;
855
856 case WINED3DDECLUSAGE_NORMAL:
857 TRACE("normal%u", semantic->usage_idx);
858 break;
859
860 case WINED3DDECLUSAGE_PSIZE:
861 TRACE("psize");
862 break;
863
864 case WINED3DDECLUSAGE_COLOR:
865 if (semantic->usage_idx == 0) TRACE("color");
866 else TRACE("specular%u", (semantic->usage_idx - 1));
867 break;
868
869 case WINED3DDECLUSAGE_TEXCOORD:
870 TRACE("texture%u", semantic->usage_idx);
871 break;
872
873 case WINED3DDECLUSAGE_TANGENT:
874 TRACE("tangent");
875 break;
876
877 case WINED3DDECLUSAGE_BINORMAL:
878 TRACE("binormal");
879 break;
880
881 case WINED3DDECLUSAGE_TESSFACTOR:
882 TRACE("tessfactor");
883 break;
884
885 case WINED3DDECLUSAGE_POSITIONT:
886 TRACE("positionT%u", semantic->usage_idx);
887 break;
888
889 case WINED3DDECLUSAGE_FOG:
890 TRACE("fog");
891 break;
892
893 case WINED3DDECLUSAGE_DEPTH:
894 TRACE("depth");
895 break;
896
897 case WINED3DDECLUSAGE_SAMPLE:
898 TRACE("sample");
899 break;
900
901 default:
902 FIXME("unknown_semantics(0x%08x)", semantic->usage);
903 }
904 }
905}
906
907static void shader_dump_register(const struct wined3d_shader_register *reg,
908 const struct wined3d_shader_version *shader_version)
909{
910 static const char * const rastout_reg_names[] = {"oPos", "oFog", "oPts"};
911 static const char * const misctype_reg_names[] = {"vPos", "vFace"};
912 UINT offset = reg->idx;
913
914 switch (reg->type)
915 {
916 case WINED3DSPR_TEMP:
917 TRACE("r");
918 break;
919
920 case WINED3DSPR_INPUT:
921 TRACE("v");
922 break;
923
924 case WINED3DSPR_CONST:
925 case WINED3DSPR_CONST2:
926 case WINED3DSPR_CONST3:
927 case WINED3DSPR_CONST4:
928 TRACE("c");
929 offset = shader_get_float_offset(reg->type, reg->idx);
930 break;
931
932 case WINED3DSPR_TEXTURE: /* vs: case WINED3DSPR_ADDR */
933 TRACE("%c", shader_version->type == WINED3D_SHADER_TYPE_PIXEL ? 't' : 'a');
934 break;
935
936 case WINED3DSPR_RASTOUT:
937 TRACE("%s", rastout_reg_names[reg->idx]);
938 break;
939
940 case WINED3DSPR_COLOROUT:
941 TRACE("oC");
942 break;
943
944 case WINED3DSPR_DEPTHOUT:
945 TRACE("oDepth");
946 break;
947
948 case WINED3DSPR_ATTROUT:
949 TRACE("oD");
950 break;
951
952 case WINED3DSPR_TEXCRDOUT:
953 /* Vertex shaders >= 3.0 use general purpose output registers
954 * (WINED3DSPR_OUTPUT), which can include an address token. */
955 if (shader_version->major >= 3) TRACE("o");
956 else TRACE("oT");
957 break;
958
959 case WINED3DSPR_CONSTINT:
960 TRACE("i");
961 break;
962
963 case WINED3DSPR_CONSTBOOL:
964 TRACE("b");
965 break;
966
967 case WINED3DSPR_LABEL:
968 TRACE("l");
969 break;
970
971 case WINED3DSPR_LOOP:
972 TRACE("aL");
973 break;
974
975 case WINED3DSPR_SAMPLER:
976 TRACE("s");
977 break;
978
979 case WINED3DSPR_MISCTYPE:
980 if (reg->idx > 1) FIXME("Unhandled misctype register %u.\n", reg->idx);
981 else TRACE("%s", misctype_reg_names[reg->idx]);
982 break;
983
984 case WINED3DSPR_PREDICATE:
985 TRACE("p");
986 break;
987
988 case WINED3DSPR_IMMCONST:
989 TRACE("l");
990 break;
991
992 case WINED3DSPR_CONSTBUFFER:
993 TRACE("cb");
994 break;
995
996 default:
997 TRACE("unhandled_rtype(%#x)", reg->type);
998 break;
999 }
1000
1001 if (reg->type == WINED3DSPR_IMMCONST)
1002 {
1003 TRACE("(");
1004 switch (reg->immconst_type)
1005 {
1006 case WINED3D_IMMCONST_FLOAT:
1007 TRACE("%.8e", *(const float *)reg->immconst_data);
1008 break;
1009
1010 case WINED3D_IMMCONST_FLOAT4:
1011 TRACE("%.8e, %.8e, %.8e, %.8e",
1012 *(const float *)&reg->immconst_data[0], *(const float *)&reg->immconst_data[1],
1013 *(const float *)&reg->immconst_data[2], *(const float *)&reg->immconst_data[3]);
1014 break;
1015
1016 default:
1017 TRACE("<unhandled immconst_type %#x>", reg->immconst_type);
1018 break;
1019 }
1020 TRACE(")");
1021 }
1022 else if (reg->type != WINED3DSPR_RASTOUT && reg->type != WINED3DSPR_MISCTYPE)
1023 {
1024 if (reg->array_idx != ~0U)
1025 {
1026 TRACE("%u[%u", offset, reg->array_idx);
1027 if (reg->rel_addr)
1028 {
1029 TRACE(" + ");
1030 shader_dump_src_param(reg->rel_addr, shader_version);
1031 }
1032 TRACE("]");
1033 }
1034 else
1035 {
1036 if (reg->rel_addr)
1037 {
1038 TRACE("[");
1039 shader_dump_src_param(reg->rel_addr, shader_version);
1040 TRACE(" + ");
1041 }
1042 TRACE("%u", offset);
1043 if (reg->rel_addr) TRACE("]");
1044 }
1045 }
1046}
1047
1048void shader_dump_dst_param(const struct wined3d_shader_dst_param *param,
1049 const struct wined3d_shader_version *shader_version)
1050{
1051 DWORD write_mask = param->write_mask;
1052
1053 shader_dump_register(&param->reg, shader_version);
1054
1055 if (write_mask != WINED3DSP_WRITEMASK_ALL)
1056 {
1057 static const char *write_mask_chars = "xyzw";
1058
1059 TRACE(".");
1060 if (write_mask & WINED3DSP_WRITEMASK_0) TRACE("%c", write_mask_chars[0]);
1061 if (write_mask & WINED3DSP_WRITEMASK_1) TRACE("%c", write_mask_chars[1]);
1062 if (write_mask & WINED3DSP_WRITEMASK_2) TRACE("%c", write_mask_chars[2]);
1063 if (write_mask & WINED3DSP_WRITEMASK_3) TRACE("%c", write_mask_chars[3]);
1064 }
1065}
1066
1067void shader_dump_src_param(const struct wined3d_shader_src_param *param,
1068 const struct wined3d_shader_version *shader_version)
1069{
1070 DWORD src_modifier = param->modifiers;
1071 DWORD swizzle = param->swizzle;
1072
1073 if (src_modifier == WINED3DSPSM_NEG
1074 || src_modifier == WINED3DSPSM_BIASNEG
1075 || src_modifier == WINED3DSPSM_SIGNNEG
1076 || src_modifier == WINED3DSPSM_X2NEG
1077 || src_modifier == WINED3DSPSM_ABSNEG)
1078 TRACE("-");
1079 else if (src_modifier == WINED3DSPSM_COMP)
1080 TRACE("1-");
1081 else if (src_modifier == WINED3DSPSM_NOT)
1082 TRACE("!");
1083
1084 if (src_modifier == WINED3DSPSM_ABS || src_modifier == WINED3DSPSM_ABSNEG)
1085 TRACE("abs(");
1086
1087 shader_dump_register(&param->reg, shader_version);
1088
1089 if (src_modifier)
1090 {
1091 switch (src_modifier)
1092 {
1093 case WINED3DSPSM_NONE: break;
1094 case WINED3DSPSM_NEG: break;
1095 case WINED3DSPSM_NOT: break;
1096 case WINED3DSPSM_BIAS: TRACE("_bias"); break;
1097 case WINED3DSPSM_BIASNEG: TRACE("_bias"); break;
1098 case WINED3DSPSM_SIGN: TRACE("_bx2"); break;
1099 case WINED3DSPSM_SIGNNEG: TRACE("_bx2"); break;
1100 case WINED3DSPSM_COMP: break;
1101 case WINED3DSPSM_X2: TRACE("_x2"); break;
1102 case WINED3DSPSM_X2NEG: TRACE("_x2"); break;
1103 case WINED3DSPSM_DZ: TRACE("_dz"); break;
1104 case WINED3DSPSM_DW: TRACE("_dw"); break;
1105 case WINED3DSPSM_ABSNEG: TRACE(")"); break;
1106 case WINED3DSPSM_ABS: TRACE(")"); break;
1107 default: TRACE("_unknown_modifier(%#x)", src_modifier);
1108 }
1109 }
1110
1111 if (swizzle != WINED3DSP_NOSWIZZLE)
1112 {
1113 static const char *swizzle_chars = "xyzw";
1114 DWORD swizzle_x = swizzle & 0x03;
1115 DWORD swizzle_y = (swizzle >> 2) & 0x03;
1116 DWORD swizzle_z = (swizzle >> 4) & 0x03;
1117 DWORD swizzle_w = (swizzle >> 6) & 0x03;
1118
1119 if (swizzle_x == swizzle_y
1120 && swizzle_x == swizzle_z
1121 && swizzle_x == swizzle_w)
1122 {
1123 TRACE(".%c", swizzle_chars[swizzle_x]);
1124 }
1125 else
1126 {
1127 TRACE(".%c%c%c%c", swizzle_chars[swizzle_x], swizzle_chars[swizzle_y],
1128 swizzle_chars[swizzle_z], swizzle_chars[swizzle_w]);
1129 }
1130 }
1131}
1132
1133/* Shared code in order to generate the bulk of the shader string.
1134 * NOTE: A description of how to parse tokens can be found on MSDN. */
1135void shader_generate_main(IWineD3DBaseShader *iface, struct wined3d_shader_buffer *buffer,
1136 const shader_reg_maps *reg_maps, const DWORD *byte_code, void *backend_ctx)
1137{
1138 IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)iface;
1139 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)shader->baseShader.device;
1140 const struct wined3d_shader_frontend *fe = shader->baseShader.frontend;
1141 void *fe_data = shader->baseShader.frontend_data;
1142 struct wined3d_shader_src_param src_rel_addr[4];
1143 struct wined3d_shader_src_param src_param[4];
1144 struct wined3d_shader_version shader_version;
1145 struct wined3d_shader_src_param dst_rel_addr;
1146 struct wined3d_shader_dst_param dst_param;
1147 struct wined3d_shader_instruction ins;
1148 struct wined3d_shader_context ctx;
1149 const DWORD *ptr = byte_code;
1150 DWORD i;
1151
1152 /* Initialize current parsing state. */
1153 ctx.shader = iface;
1154 ctx.gl_info = &device->adapter->gl_info;
1155 ctx.reg_maps = reg_maps;
1156 ctx.buffer = buffer;
1157 ctx.backend_data = backend_ctx;
1158
1159 ins.ctx = &ctx;
1160 ins.dst = &dst_param;
1161 ins.src = src_param;
1162 shader->baseShader.parse_state.current_row = 0;
1163
1164 fe->shader_read_header(fe_data, &ptr, &shader_version);
1165
1166 while (!fe->shader_is_end(fe_data, &ptr))
1167 {
1168 const char *comment;
1169 UINT comment_size;
1170 UINT param_size;
1171
1172 /* Skip comment tokens. */
1173 fe->shader_read_comment(&ptr, &comment, &comment_size);
1174 if (comment) continue;
1175
1176 /* Read opcode. */
1177 fe->shader_read_opcode(fe_data, &ptr, &ins, &param_size);
1178
1179 /* Unknown opcode and its parameters. */
1180 if (ins.handler_idx == WINED3DSIH_TABLE_SIZE)
1181 {
1182 TRACE("Skipping unrecognized instruction.\n");
1183 ptr += param_size;
1184 continue;
1185 }
1186
1187 /* Nothing to do. */
1188 if (ins.handler_idx == WINED3DSIH_DCL
1189 || ins.handler_idx == WINED3DSIH_NOP
1190 || ins.handler_idx == WINED3DSIH_DEF
1191 || ins.handler_idx == WINED3DSIH_DEFI
1192 || ins.handler_idx == WINED3DSIH_DEFB
1193 || ins.handler_idx == WINED3DSIH_PHASE)
1194 {
1195 ptr += param_size;
1196 continue;
1197 }
1198
1199 /* Destination token */
1200 if (ins.dst_count) fe->shader_read_dst_param(fe_data, &ptr, &dst_param, &dst_rel_addr);
1201
1202 /* Predication token */
1203 if (ins.predicate)
1204 {
1205#ifndef VBOX_WITH_VMSVGA
1206 FIXME("Predicates not implemented.\n");
1207#endif
1208 ins.predicate = *ptr++;
1209 }
1210
1211 /* Other source tokens */
1212 for (i = 0; i < ins.src_count; ++i)
1213 {
1214 fe->shader_read_src_param(fe_data, &ptr, &src_param[i], &src_rel_addr[i]);
1215 }
1216
1217 /* Call appropriate function for output target */
1218 device->shader_backend->shader_handle_instruction(&ins);
1219 }
1220}
1221
1222static void shader_dump_ins_modifiers(const struct wined3d_shader_dst_param *dst)
1223{
1224 DWORD mmask = dst->modifiers;
1225
1226 switch (dst->shift)
1227 {
1228 case 0: break;
1229 case 13: TRACE("_d8"); break;
1230 case 14: TRACE("_d4"); break;
1231 case 15: TRACE("_d2"); break;
1232 case 1: TRACE("_x2"); break;
1233 case 2: TRACE("_x4"); break;
1234 case 3: TRACE("_x8"); break;
1235 default: TRACE("_unhandled_shift(%d)", dst->shift); break;
1236 }
1237
1238 if (mmask & WINED3DSPDM_SATURATE) TRACE("_sat");
1239 if (mmask & WINED3DSPDM_PARTIALPRECISION) TRACE("_pp");
1240 if (mmask & WINED3DSPDM_MSAMPCENTROID) TRACE("_centroid");
1241
1242 mmask &= ~(WINED3DSPDM_SATURATE | WINED3DSPDM_PARTIALPRECISION | WINED3DSPDM_MSAMPCENTROID);
1243 if (mmask) FIXME("_unrecognized_modifier(%#x)", mmask);
1244}
1245
1246static void shader_trace_init(const struct wined3d_shader_frontend *fe, void *fe_data, const DWORD *byte_code)
1247{
1248 struct wined3d_shader_version shader_version;
1249 const DWORD *ptr = byte_code;
1250 const char *type_prefix;
1251 DWORD i;
1252
1253 TRACE("Parsing %p.\n", byte_code);
1254
1255 fe->shader_read_header(fe_data, &ptr, &shader_version);
1256
1257 switch (shader_version.type)
1258 {
1259 case WINED3D_SHADER_TYPE_VERTEX:
1260 type_prefix = "vs";
1261 break;
1262
1263 case WINED3D_SHADER_TYPE_GEOMETRY:
1264 type_prefix = "gs";
1265 break;
1266
1267 case WINED3D_SHADER_TYPE_PIXEL:
1268 type_prefix = "ps";
1269 break;
1270
1271 default:
1272 FIXME("Unhandled shader type %#x.\n", shader_version.type);
1273 type_prefix = "unknown";
1274 break;
1275 }
1276
1277 TRACE("%s_%u_%u\n", type_prefix, shader_version.major, shader_version.minor);
1278
1279 while (!fe->shader_is_end(fe_data, &ptr))
1280 {
1281 struct wined3d_shader_instruction ins;
1282 const char *comment;
1283 UINT comment_size;
1284 UINT param_size;
1285
1286 /* comment */
1287 fe->shader_read_comment(&ptr, &comment, &comment_size);
1288 if (comment)
1289 {
1290 if (comment_size > 4 && *(const DWORD *)comment == WINEMAKEFOURCC('T', 'E', 'X', 'T'))
1291 {
1292 const char *end = comment + comment_size;
1293 const char *cur = comment + 4;
1294 const char *line = cur;
1295
1296 TRACE("// TEXT\n");
1297 while (cur != end)
1298 {
1299 if (*cur == '\n')
1300 {
1301 UINT len = cur - line;
1302 if (len && *(cur - 1) == '\r') --len;
1303 TRACE("// %s\n", debugstr_an(line, len));
1304 line = ++cur;
1305 }
1306 else ++cur;
1307 }
1308 if (line != cur) TRACE("// %s\n", debugstr_an(line, cur - line));
1309 }
1310 else TRACE("// %s\n", debugstr_an(comment, comment_size));
1311 continue;
1312 }
1313
1314 fe->shader_read_opcode(fe_data, &ptr, &ins, &param_size);
1315 if (ins.handler_idx == WINED3DSIH_TABLE_SIZE)
1316 {
1317 TRACE("Skipping unrecognized instruction.\n");
1318 ptr += param_size;
1319 continue;
1320 }
1321
1322 if (ins.handler_idx == WINED3DSIH_DCL)
1323 {
1324 struct wined3d_shader_semantic semantic;
1325
1326 fe->shader_read_semantic(&ptr, &semantic);
1327
1328 shader_dump_decl_usage(&semantic, &shader_version);
1329 shader_dump_ins_modifiers(&semantic.reg);
1330 TRACE(" ");
1331 shader_dump_dst_param(&semantic.reg, &shader_version);
1332 }
1333 else if (ins.handler_idx == WINED3DSIH_DEF)
1334 {
1335 struct wined3d_shader_src_param rel_addr;
1336 struct wined3d_shader_dst_param dst;
1337
1338 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
1339
1340 TRACE("def c%u = %f, %f, %f, %f", shader_get_float_offset(dst.reg.type, dst.reg.idx),
1341 *(const float *)(ptr),
1342 *(const float *)(ptr + 1),
1343 *(const float *)(ptr + 2),
1344 *(const float *)(ptr + 3));
1345 ptr += 4;
1346 }
1347 else if (ins.handler_idx == WINED3DSIH_DEFI)
1348 {
1349 struct wined3d_shader_src_param rel_addr;
1350 struct wined3d_shader_dst_param dst;
1351
1352 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
1353
1354 TRACE("defi i%u = %d, %d, %d, %d", dst.reg.idx,
1355 *(ptr),
1356 *(ptr + 1),
1357 *(ptr + 2),
1358 *(ptr + 3));
1359 ptr += 4;
1360 }
1361 else if (ins.handler_idx == WINED3DSIH_DEFB)
1362 {
1363 struct wined3d_shader_src_param rel_addr;
1364 struct wined3d_shader_dst_param dst;
1365
1366 fe->shader_read_dst_param(fe_data, &ptr, &dst, &rel_addr);
1367
1368 TRACE("defb b%u = %s", dst.reg.idx, *ptr ? "true" : "false");
1369 ++ptr;
1370 }
1371 else
1372 {
1373 struct wined3d_shader_src_param dst_rel_addr, src_rel_addr;
1374 struct wined3d_shader_dst_param dst_param;
1375 struct wined3d_shader_src_param src_param;
1376
1377 if (ins.dst_count)
1378 {
1379 fe->shader_read_dst_param(fe_data, &ptr, &dst_param, &dst_rel_addr);
1380 }
1381
1382 /* Print out predication source token first - it follows
1383 * the destination token. */
1384 if (ins.predicate)
1385 {
1386 fe->shader_read_src_param(fe_data, &ptr, &src_param, &src_rel_addr);
1387 TRACE("(");
1388 shader_dump_src_param(&src_param, &shader_version);
1389 TRACE(") ");
1390 }
1391
1392 /* PixWin marks instructions with the coissue flag with a '+' */
1393 if (ins.coissue) TRACE("+");
1394
1395 TRACE("%s", shader_opcode_names[ins.handler_idx]);
1396
1397 if (ins.handler_idx == WINED3DSIH_IFC
1398 || ins.handler_idx == WINED3DSIH_BREAKC)
1399 {
1400 switch (ins.flags)
1401 {
1402 case COMPARISON_GT: TRACE("_gt"); break;
1403 case COMPARISON_EQ: TRACE("_eq"); break;
1404 case COMPARISON_GE: TRACE("_ge"); break;
1405 case COMPARISON_LT: TRACE("_lt"); break;
1406 case COMPARISON_NE: TRACE("_ne"); break;
1407 case COMPARISON_LE: TRACE("_le"); break;
1408 default: TRACE("_(%u)", ins.flags);
1409 }
1410 }
1411 else if (ins.handler_idx == WINED3DSIH_TEX
1412 && shader_version.major >= 2
1413 && (ins.flags & WINED3DSI_TEXLD_PROJECT))
1414 {
1415 TRACE("p");
1416 }
1417
1418 /* We already read the destination token, print it. */
1419 if (ins.dst_count)
1420 {
1421 shader_dump_ins_modifiers(&dst_param);
1422 TRACE(" ");
1423 shader_dump_dst_param(&dst_param, &shader_version);
1424 }
1425
1426 /* Other source tokens */
1427 for (i = ins.dst_count; i < (ins.dst_count + ins.src_count); ++i)
1428 {
1429 fe->shader_read_src_param(fe_data, &ptr, &src_param, &src_rel_addr);
1430 TRACE(!i ? " " : ", ");
1431 shader_dump_src_param(&src_param, &shader_version);
1432 }
1433 }
1434 TRACE("\n");
1435 }
1436}
1437
1438static void shader_cleanup(IWineD3DBaseShader *iface)
1439{
1440 IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)iface;
1441
1442 ((IWineD3DDeviceImpl *)shader->baseShader.device)->shader_backend->shader_destroy(iface);
1443 HeapFree(GetProcessHeap(), 0, shader->baseShader.reg_maps.constf);
1444 HeapFree(GetProcessHeap(), 0, shader->baseShader.function);
1445 shader_delete_constant_list(&shader->baseShader.constantsF);
1446 shader_delete_constant_list(&shader->baseShader.constantsB);
1447 shader_delete_constant_list(&shader->baseShader.constantsI);
1448 list_remove(&shader->baseShader.shader_list_entry);
1449
1450 if (shader->baseShader.frontend && shader->baseShader.frontend_data)
1451 {
1452 shader->baseShader.frontend->shader_free(shader->baseShader.frontend_data);
1453 }
1454}
1455
1456static void shader_none_handle_instruction(const struct wined3d_shader_instruction *ins) {}
1457static void shader_none_select(const struct wined3d_context *context, BOOL usePS, BOOL useVS) {}
1458static void shader_none_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type) {}
1459static void shader_none_deselect_depth_blt(IWineD3DDevice *iface) {}
1460static void shader_none_update_float_vertex_constants(IWineD3DDevice *iface, UINT start, UINT count) {}
1461static void shader_none_update_float_pixel_constants(IWineD3DDevice *iface, UINT start, UINT count) {}
1462static void shader_none_load_constants(const struct wined3d_context *context, char usePS, char useVS) {}
1463static void shader_none_load_np2fixup_constants(IWineD3DDevice *iface, char usePS, char useVS) {}
1464static void shader_none_destroy(IWineD3DBaseShader *iface) {}
1465static HRESULT shader_none_alloc(IWineD3DDevice *iface) {return WINED3D_OK;}
1466static void shader_none_free(IWineD3DDevice *iface) {}
1467static BOOL shader_none_dirty_const(IWineD3DDevice *iface) {return FALSE;}
1468
1469static void shader_none_get_caps(const struct wined3d_gl_info *gl_info, struct shader_caps *caps)
1470{
1471 /* Set the shader caps to 0 for the none shader backend */
1472 caps->VertexShaderVersion = 0;
1473 caps->PixelShaderVersion = 0;
1474 caps->PixelShader1xMaxValue = 0.0f;
1475}
1476
1477static BOOL shader_none_color_fixup_supported(struct color_fixup_desc fixup)
1478{
1479 if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
1480 {
1481 TRACE("Checking support for fixup:\n");
1482 dump_color_fixup_desc(fixup);
1483 }
1484
1485 /* Faked to make some apps happy. */
1486 if (!is_complex_fixup(fixup))
1487 {
1488 TRACE("[OK]\n");
1489 return TRUE;
1490 }
1491
1492 TRACE("[FAILED]\n");
1493 return FALSE;
1494}
1495
1496const shader_backend_t none_shader_backend = {
1497 shader_none_handle_instruction,
1498 shader_none_select,
1499 shader_none_select_depth_blt,
1500 shader_none_deselect_depth_blt,
1501 shader_none_update_float_vertex_constants,
1502 shader_none_update_float_pixel_constants,
1503 shader_none_load_constants,
1504 shader_none_load_np2fixup_constants,
1505 shader_none_destroy,
1506 shader_none_alloc,
1507 shader_none_free,
1508 shader_none_dirty_const,
1509 shader_none_get_caps,
1510 shader_none_color_fixup_supported,
1511};
1512
1513static void shader_get_parent(IWineD3DBaseShaderImpl *shader, IUnknown **parent)
1514{
1515 *parent = shader->baseShader.parent;
1516 IUnknown_AddRef(*parent);
1517 TRACE("shader %p, returning %p.\n", shader, *parent);
1518}
1519
1520static HRESULT shader_get_function(IWineD3DBaseShaderImpl *shader, void *data, UINT *data_size)
1521{
1522 if (!data)
1523 {
1524 *data_size = shader->baseShader.functionLength;
1525 return WINED3D_OK;
1526 }
1527
1528 if (*data_size < shader->baseShader.functionLength)
1529 {
1530 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
1531 * than the required size we should write the required size and
1532 * return D3DERR_MOREDATA. That's not actually true. */
1533 return WINED3DERR_INVALIDCALL;
1534 }
1535
1536 memcpy(data, shader->baseShader.function, shader->baseShader.functionLength);
1537
1538 return WINED3D_OK;
1539}
1540
1541static HRESULT shader_set_function(IWineD3DBaseShaderImpl *shader, const DWORD *byte_code,
1542 const struct wined3d_shader_signature *output_signature, DWORD float_const_count)
1543{
1544 struct shader_reg_maps *reg_maps = &shader->baseShader.reg_maps;
1545 const struct wined3d_shader_frontend *fe;
1546 HRESULT hr;
1547
1548 TRACE("shader %p, byte_code %p, output_signature %p, float_const_count %u.\n",
1549 shader, byte_code, output_signature, float_const_count);
1550
1551 fe = shader_select_frontend(*byte_code);
1552 if (!fe)
1553 {
1554 FIXME("Unable to find frontend for shader.\n");
1555 return WINED3DERR_INVALIDCALL;
1556 }
1557 shader->baseShader.frontend = fe;
1558 shader->baseShader.frontend_data = fe->shader_init(byte_code, output_signature);
1559 if (!shader->baseShader.frontend_data)
1560 {
1561 FIXME("Failed to initialize frontend.\n");
1562 return WINED3DERR_INVALIDCALL;
1563 }
1564
1565 /* First pass: trace shader. */
1566 if (TRACE_ON(d3d_shader)) shader_trace_init(fe, shader->baseShader.frontend_data, byte_code);
1567
1568 /* Initialize immediate constant lists. */
1569 list_init(&shader->baseShader.constantsF);
1570 list_init(&shader->baseShader.constantsB);
1571 list_init(&shader->baseShader.constantsI);
1572
1573 /* Second pass: figure out which registers are used, what the semantics are, etc. */
1574 hr = shader_get_registers_used((IWineD3DBaseShader *)shader, fe,
1575 reg_maps, shader->baseShader.input_signature, shader->baseShader.output_signature,
1576 byte_code, float_const_count);
1577 if (FAILED(hr)) return hr;
1578
1579 shader->baseShader.function = HeapAlloc(GetProcessHeap(), 0, shader->baseShader.functionLength);
1580 if (!shader->baseShader.function) return E_OUTOFMEMORY;
1581 memcpy(shader->baseShader.function, byte_code, shader->baseShader.functionLength);
1582
1583 return WINED3D_OK;
1584}
1585
1586static HRESULT STDMETHODCALLTYPE vertexshader_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, void **object)
1587{
1588 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
1589
1590 if (IsEqualGUID(riid, &IID_IWineD3DVertexShader)
1591 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
1592 || IsEqualGUID(riid, &IID_IWineD3DBase)
1593 || IsEqualGUID(riid, &IID_IUnknown))
1594 {
1595 IUnknown_AddRef(iface);
1596 *object = iface;
1597 return S_OK;
1598 }
1599
1600 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
1601
1602 *object = NULL;
1603 return E_NOINTERFACE;
1604}
1605
1606static ULONG STDMETHODCALLTYPE vertexshader_AddRef(IWineD3DVertexShader *iface)
1607{
1608 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
1609 ULONG refcount = InterlockedIncrement(&shader->baseShader.ref);
1610
1611 TRACE("%p increasing refcount to %u.\n", shader, refcount);
1612
1613 return refcount;
1614}
1615
1616#ifdef VBOX_WINE_WITH_SHADER_CACHE
1617static void shader_chache_put(PVBOXEXT_HASHCACHE pCache, IWineD3DBaseShaderImpl *pShader);
1618#endif
1619
1620static ULONG STDMETHODCALLTYPE vertexshader_Release(IWineD3DVertexShader *iface)
1621{
1622 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
1623 ULONG refcount = InterlockedDecrement(&shader->baseShader.ref);
1624
1625 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
1626
1627 if (!refcount)
1628 {
1629#ifdef VBOX_WINE_WITH_SHADER_CACHE
1630 shader_chache_put(&((IWineD3DDeviceImpl*)shader->baseShader.device)->vshaderCache, (IWineD3DBaseShaderImpl*)shader);
1631#else
1632 shader_cleanup((IWineD3DBaseShader *)iface);
1633#ifndef VBOX_WITH_VMSVGA
1634 shader->baseShader.parent_ops->wined3d_object_destroyed(shader->baseShader.parent);
1635#endif
1636 HeapFree(GetProcessHeap(), 0, shader);
1637#endif
1638 }
1639
1640 return refcount;
1641}
1642
1643static HRESULT STDMETHODCALLTYPE vertexshader_GetParent(IWineD3DVertexShader *iface, IUnknown **parent)
1644{
1645 TRACE("iface %p, parent %p.\n", iface, parent);
1646
1647 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
1648
1649 return WINED3D_OK;
1650}
1651
1652static HRESULT STDMETHODCALLTYPE vertexshader_GetFunction(IWineD3DVertexShader *iface, void *data, UINT *data_size)
1653{
1654 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
1655
1656 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
1657}
1658
1659/* Set local constants for d3d8 shaders. */
1660static HRESULT STDMETHODCALLTYPE vertexshader_SetLocalConstantsF(IWineD3DVertexShader *iface,
1661 UINT start_idx, const float *src_data, UINT count)
1662{
1663 IWineD3DVertexShaderImpl *shader =(IWineD3DVertexShaderImpl *)iface;
1664 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)shader->baseShader.device;
1665 UINT i, end_idx;
1666
1667 TRACE("iface %p, start_idx %u, src_data %p, count %u.\n", iface, start_idx, src_data, count);
1668
1669 end_idx = start_idx + count;
1670 if (end_idx > device->d3d_vshader_constantF)
1671 {
1672 WARN("end_idx %u > float constants limit %u.\n", end_idx, device->d3d_vshader_constantF);
1673 end_idx = device->d3d_vshader_constantF;
1674 }
1675
1676 for (i = start_idx; i < end_idx; ++i)
1677 {
1678 local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
1679 if (!lconst) return E_OUTOFMEMORY;
1680
1681 lconst->idx = i;
1682 memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
1683 list_add_head(&shader->baseShader.constantsF, &lconst->entry);
1684 }
1685
1686 return WINED3D_OK;
1687}
1688
1689static const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
1690{
1691 /* IUnknown methods */
1692 vertexshader_QueryInterface,
1693 vertexshader_AddRef,
1694 vertexshader_Release,
1695 /* IWineD3DBase methods */
1696 vertexshader_GetParent,
1697 /* IWineD3DBaseShader methods */
1698 vertexshader_GetFunction,
1699 /* IWineD3DVertexShader methods */
1700 vertexshader_SetLocalConstantsF,
1701};
1702
1703void find_vs_compile_args(IWineD3DVertexShaderImpl *shader,
1704 IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args)
1705{
1706 args->fog_src = stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE ? VS_FOG_COORD : VS_FOG_Z;
1707 args->clip_enabled = stateblock->renderState[WINED3DRS_CLIPPING]
1708 && stateblock->renderState[WINED3DRS_CLIPPLANEENABLE];
1709 args->swizzle_map = ((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.swizzle_map;
1710}
1711
1712static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2)
1713{
1714 if (usage_idx1 != usage_idx2) return FALSE;
1715 if (usage1 == usage2) return TRUE;
1716 if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
1717 if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
1718
1719 return FALSE;
1720}
1721
1722BOOL vshader_get_input(IWineD3DVertexShader *iface, BYTE usage_req, BYTE usage_idx_req, unsigned int *regnum)
1723{
1724 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
1725 WORD map = shader->baseShader.reg_maps.input_registers;
1726 unsigned int i;
1727
1728 for (i = 0; map; map >>= 1, ++i)
1729 {
1730 if (!(map & 1)) continue;
1731
1732 if (match_usage(shader->attributes[i].usage,
1733 shader->attributes[i].usage_idx, usage_req, usage_idx_req))
1734 {
1735 *regnum = i;
1736 return TRUE;
1737 }
1738 }
1739 return FALSE;
1740}
1741
1742static void vertexshader_set_limits(IWineD3DVertexShaderImpl *shader)
1743{
1744 DWORD shader_version = WINED3D_SHADER_VERSION(shader->baseShader.reg_maps.shader_version.major,
1745 shader->baseShader.reg_maps.shader_version.minor);
1746 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)shader->baseShader.device;
1747
1748 shader->baseShader.limits.texcoord = 0;
1749 shader->baseShader.limits.attributes = 16;
1750 shader->baseShader.limits.packed_input = 0;
1751
1752 switch (shader_version)
1753 {
1754 case WINED3D_SHADER_VERSION(1, 0):
1755 case WINED3D_SHADER_VERSION(1, 1):
1756 shader->baseShader.limits.temporary = 12;
1757 shader->baseShader.limits.constant_bool = 0;
1758 shader->baseShader.limits.constant_int = 0;
1759 shader->baseShader.limits.address = 1;
1760 shader->baseShader.limits.packed_output = 0;
1761 shader->baseShader.limits.sampler = 0;
1762 shader->baseShader.limits.label = 0;
1763 /* TODO: vs_1_1 has a minimum of 96 constants. What happens when
1764 * a vs_1_1 shader is used on a vs_3_0 capable card that has 256
1765 * constants? */
1766 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
1767 break;
1768
1769 case WINED3D_SHADER_VERSION(2, 0):
1770 case WINED3D_SHADER_VERSION(2, 1):
1771 shader->baseShader.limits.temporary = 12;
1772 shader->baseShader.limits.constant_bool = 16;
1773 shader->baseShader.limits.constant_int = 16;
1774 shader->baseShader.limits.address = 1;
1775 shader->baseShader.limits.packed_output = 0;
1776 shader->baseShader.limits.sampler = 0;
1777 shader->baseShader.limits.label = 16;
1778 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
1779 break;
1780
1781 case WINED3D_SHADER_VERSION(4, 0):
1782 FIXME("Using 3.0 limits for 4.0 shader.\n");
1783 RT_FALL_THRU();
1784
1785 case WINED3D_SHADER_VERSION(3, 0):
1786 shader->baseShader.limits.temporary = 32;
1787 shader->baseShader.limits.constant_bool = 32;
1788 shader->baseShader.limits.constant_int = 32;
1789 shader->baseShader.limits.address = 1;
1790 shader->baseShader.limits.packed_output = 12;
1791 shader->baseShader.limits.sampler = 4;
1792 shader->baseShader.limits.label = 16; /* FIXME: 2048 */
1793 /* DX10 cards on Windows advertise a d3d9 constant limit of 256
1794 * even though they are capable of supporting much more (GL
1795 * drivers advertise 1024). d3d9.dll and d3d8.dll clamp the
1796 * wined3d-advertised maximum. Clamp the constant limit for <= 3.0
1797 * shaders to 256. */
1798 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
1799 break;
1800
1801 default:
1802 shader->baseShader.limits.temporary = 12;
1803 shader->baseShader.limits.constant_bool = 16;
1804 shader->baseShader.limits.constant_int = 16;
1805 shader->baseShader.limits.address = 1;
1806 shader->baseShader.limits.packed_output = 0;
1807 shader->baseShader.limits.sampler = 0;
1808 shader->baseShader.limits.label = 16;
1809 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
1810 FIXME("Unrecognized vertex shader version \"%u.%u\".\n",
1811 shader->baseShader.reg_maps.shader_version.major,
1812 shader->baseShader.reg_maps.shader_version.minor);
1813 }
1814}
1815
1816HRESULT vertexshader_init(IWineD3DVertexShaderImpl *shader, IWineD3DDeviceImpl *device,
1817 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1818 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1819{
1820 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1821 struct shader_reg_maps *reg_maps = &shader->baseShader.reg_maps;
1822 unsigned int i;
1823 HRESULT hr;
1824 WORD map;
1825
1826 if (!byte_code) return WINED3DERR_INVALIDCALL;
1827
1828 shader->lpVtbl = &IWineD3DVertexShader_Vtbl;
1829 shader_init(&shader->baseShader, device, parent, parent_ops);
1830
1831 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code,
1832 output_signature, device->d3d_vshader_constantF);
1833 if (FAILED(hr))
1834 {
1835 WARN("Failed to set function, hr %#x.\n", hr);
1836 shader_cleanup((IWineD3DBaseShader *)shader);
1837 return hr;
1838 }
1839
1840 map = shader->baseShader.reg_maps.input_registers;
1841 for (i = 0; map; map >>= 1, ++i)
1842 {
1843 if (!(map & 1) || !shader->baseShader.input_signature[i].semantic_name) continue;
1844
1845 shader->attributes[i].usage =
1846 shader_usage_from_semantic_name(shader->baseShader.input_signature[i].semantic_name);
1847 shader->attributes[i].usage_idx = shader->baseShader.input_signature[i].semantic_idx;
1848 }
1849
1850 if (output_signature)
1851 {
1852 for (i = 0; i < output_signature->element_count; ++i)
1853 {
1854 struct wined3d_shader_signature_element *e = &output_signature->elements[i];
1855 reg_maps->output_registers |= 1 << e->register_idx;
1856 shader->baseShader.output_signature[e->register_idx] = *e;
1857 }
1858 }
1859
1860 vertexshader_set_limits(shader);
1861
1862 if (device->vs_selected_mode == SHADER_ARB
1863 && (gl_info->quirks & WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT)
1864 && shader->min_rel_offset <= shader->max_rel_offset)
1865 {
1866 if (shader->max_rel_offset - shader->min_rel_offset > 127)
1867 {
1868 FIXME("The difference between the minimum and maximum relative offset is > 127.\n");
1869 FIXME("Which this OpenGL implementation does not support. Try using GLSL.\n");
1870 FIXME("Min: %d, Max: %d.\n", shader->min_rel_offset, shader->max_rel_offset);
1871 }
1872 else if (shader->max_rel_offset - shader->min_rel_offset > 63)
1873 {
1874 shader->rel_offset = shader->min_rel_offset + 63;
1875 }
1876 else if (shader->max_rel_offset > 63)
1877 {
1878 shader->rel_offset = shader->min_rel_offset;
1879 }
1880 else
1881 {
1882 shader->rel_offset = 0;
1883 }
1884 }
1885
1886 shader->baseShader.load_local_constsF = shader->baseShader.reg_maps.usesrelconstF
1887 && !list_empty(&shader->baseShader.constantsF);
1888
1889 return WINED3D_OK;
1890}
1891
1892static HRESULT STDMETHODCALLTYPE geometryshader_QueryInterface(IWineD3DGeometryShader *iface,
1893 REFIID riid, void **object)
1894{
1895 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
1896
1897 if (IsEqualGUID(riid, &IID_IWineD3DGeometryShader)
1898 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
1899 || IsEqualGUID(riid, &IID_IWineD3DBase)
1900 || IsEqualGUID(riid, &IID_IUnknown))
1901 {
1902 IUnknown_AddRef(iface);
1903 *object = iface;
1904 return S_OK;
1905 }
1906
1907 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
1908
1909 *object = NULL;
1910 return E_NOINTERFACE;
1911}
1912
1913static ULONG STDMETHODCALLTYPE geometryshader_AddRef(IWineD3DGeometryShader *iface)
1914{
1915 struct wined3d_geometryshader *shader = (struct wined3d_geometryshader *)iface;
1916 ULONG refcount = InterlockedIncrement(&shader->base_shader.ref);
1917
1918 TRACE("%p increasing refcount to %u.\n", shader, refcount);
1919
1920 return refcount;
1921}
1922
1923static ULONG STDMETHODCALLTYPE geometryshader_Release(IWineD3DGeometryShader *iface)
1924{
1925 struct wined3d_geometryshader *shader = (struct wined3d_geometryshader *)iface;
1926 ULONG refcount = InterlockedDecrement(&shader->base_shader.ref);
1927
1928 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
1929
1930 if (!refcount)
1931 {
1932 shader_cleanup((IWineD3DBaseShader *)iface);
1933 shader->base_shader.parent_ops->wined3d_object_destroyed(shader->base_shader.parent);
1934 HeapFree(GetProcessHeap(), 0, shader);
1935 }
1936
1937 return refcount;
1938}
1939
1940static HRESULT STDMETHODCALLTYPE geometryshader_GetParent(IWineD3DGeometryShader *iface, IUnknown **parent)
1941{
1942 TRACE("iface %p, parent %p.\n", iface, parent);
1943
1944 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
1945
1946 return WINED3D_OK;
1947}
1948
1949static HRESULT STDMETHODCALLTYPE geometryshader_GetFunction(IWineD3DGeometryShader *iface, void *data, UINT *data_size)
1950{
1951 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
1952
1953 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
1954}
1955
1956static const IWineD3DGeometryShaderVtbl wined3d_geometryshader_vtbl =
1957{
1958 /* IUnknown methods */
1959 geometryshader_QueryInterface,
1960 geometryshader_AddRef,
1961 geometryshader_Release,
1962 /* IWineD3DBase methods */
1963 geometryshader_GetParent,
1964 /* IWineD3DBaseShader methods */
1965 geometryshader_GetFunction,
1966};
1967
1968HRESULT geometryshader_init(struct wined3d_geometryshader *shader, IWineD3DDeviceImpl *device,
1969 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1970 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1971{
1972 HRESULT hr;
1973
1974 shader->vtbl = &wined3d_geometryshader_vtbl;
1975 shader_init(&shader->base_shader, device, parent, parent_ops);
1976
1977 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code, output_signature, 0);
1978 if (FAILED(hr))
1979 {
1980 WARN("Failed to set function, hr %#x.\n", hr);
1981 shader_cleanup((IWineD3DBaseShader *)shader);
1982 return hr;
1983 }
1984
1985 shader->base_shader.load_local_constsF = FALSE;
1986
1987 return WINED3D_OK;
1988}
1989
1990static HRESULT STDMETHODCALLTYPE pixelshader_QueryInterface(IWineD3DPixelShader *iface, REFIID riid, void **object)
1991{
1992 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
1993
1994 if (IsEqualGUID(riid, &IID_IWineD3DPixelShader)
1995 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
1996 || IsEqualGUID(riid, &IID_IWineD3DBase)
1997 || IsEqualGUID(riid, &IID_IUnknown))
1998 {
1999 IUnknown_AddRef(iface);
2000 *object = iface;
2001 return S_OK;
2002 }
2003
2004 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
2005
2006 *object = NULL;
2007 return E_NOINTERFACE;
2008}
2009
2010static ULONG STDMETHODCALLTYPE pixelshader_AddRef(IWineD3DPixelShader *iface)
2011{
2012 IWineD3DPixelShaderImpl *shader = (IWineD3DPixelShaderImpl *)iface;
2013 ULONG refcount = InterlockedIncrement(&shader->baseShader.ref);
2014
2015 TRACE("%p increasing refcount to %u.\n", shader, refcount);
2016
2017 return refcount;
2018}
2019
2020static ULONG STDMETHODCALLTYPE pixelshader_Release(IWineD3DPixelShader *iface)
2021{
2022 IWineD3DPixelShaderImpl *shader = (IWineD3DPixelShaderImpl *)iface;
2023 ULONG refcount = InterlockedDecrement(&shader->baseShader.ref);
2024
2025 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
2026
2027 if (!refcount)
2028 {
2029#ifdef VBOX_WINE_WITH_SHADER_CACHE
2030 shader_chache_put(&((IWineD3DDeviceImpl*)shader->baseShader.device)->pshaderCache, (IWineD3DBaseShaderImpl*)shader);
2031#else
2032 shader_cleanup((IWineD3DBaseShader *)iface);
2033#ifndef VBOX_WITH_VMSVGA
2034 shader->baseShader.parent_ops->wined3d_object_destroyed(shader->baseShader.parent);
2035#endif
2036 HeapFree(GetProcessHeap(), 0, shader);
2037#endif
2038 }
2039
2040 return refcount;
2041}
2042
2043static HRESULT STDMETHODCALLTYPE pixelshader_GetParent(IWineD3DPixelShader *iface, IUnknown **parent)
2044{
2045 TRACE("iface %p, parent %p.\n", iface, parent);
2046
2047 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
2048
2049 return WINED3D_OK;
2050}
2051
2052static HRESULT STDMETHODCALLTYPE pixelshader_GetFunction(IWineD3DPixelShader *iface, void *data, UINT *data_size)
2053{
2054 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
2055
2056 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
2057}
2058
2059static const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl =
2060{
2061 /* IUnknown methods */
2062 pixelshader_QueryInterface,
2063 pixelshader_AddRef,
2064 pixelshader_Release,
2065 /* IWineD3DBase methods */
2066 pixelshader_GetParent,
2067 /* IWineD3DBaseShader methods */
2068 pixelshader_GetFunction
2069};
2070
2071void find_ps_compile_args(IWineD3DPixelShaderImpl *shader,
2072 IWineD3DStateBlockImpl *stateblock, struct ps_compile_args *args)
2073{
2074 IWineD3DBaseTextureImpl *texture;
2075 UINT i;
2076
2077 memset(args, 0, sizeof(*args)); /* FIXME: Make sure all bits are set. */
2078 args->srgb_correction = stateblock->renderState[WINED3DRS_SRGBWRITEENABLE] ? 1 : 0;
2079 args->np2_fixup = 0;
2080 args->t_mirror = 0;
2081
2082 if (shader->baseShader.reg_maps.shader_version.major==1
2083 && shader->baseShader.reg_maps.shader_version.minor<=3)
2084 {
2085 for (i=0; i<4; ++i)
2086 {
2087 DWORD flags = stateblock->textureState[i][WINED3DTSS_TEXTURETRANSFORMFLAGS];
2088 DWORD tex_transform = flags & ~WINED3DTTFF_PROJECTED;
2089 if (flags & WINED3DTTFF_PROJECTED)
2090 {
2091 tex_transform |= WINED3D_PSARGS_PROJECTED;
2092 }
2093 args->tex_transform |= tex_transform << (i*WINED3D_PSARGS_TEXTRANSFORM_SHIFT);
2094 }
2095 }
2096
2097 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
2098 {
2099 if (!shader->baseShader.reg_maps.sampler_type[i]) continue;
2100 texture = (IWineD3DBaseTextureImpl *)stateblock->textures[i];
2101 if (!texture)
2102 {
2103 args->color_fixup[i] = COLOR_FIXUP_IDENTITY;
2104 continue;
2105 }
2106 args->color_fixup[i] = texture->resource.format_desc->color_fixup;
2107
2108 /* Flag samplers that need NP2 texcoord fixup. */
2109 if (!texture->baseTexture.pow2Matrix_identity)
2110 {
2111 args->np2_fixup |= (1 << i);
2112 }
2113
2114 if (texture->baseTexture.t_mirror)
2115 {
2116 args->t_mirror |= (1 << i);
2117 }
2118 }
2119 if (shader->baseShader.reg_maps.shader_version.major >= 3)
2120 {
2121 if (((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.position_transformed)
2122 {
2123 args->vp_mode = pretransformed;
2124 }
2125 else if (use_vs(stateblock))
2126 {
2127 args->vp_mode = vertexshader;
2128 }
2129 else
2130 {
2131 args->vp_mode = fixedfunction;
2132 }
2133 args->fog = FOG_OFF;
2134 }
2135 else
2136 {
2137 args->vp_mode = vertexshader;
2138 if (stateblock->renderState[WINED3DRS_FOGENABLE])
2139 {
2140 switch (stateblock->renderState[WINED3DRS_FOGTABLEMODE])
2141 {
2142 case WINED3DFOG_NONE:
2143 if (((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.position_transformed
2144 || use_vs(stateblock))
2145 {
2146 args->fog = FOG_LINEAR;
2147 break;
2148 }
2149
2150 switch (stateblock->renderState[WINED3DRS_FOGVERTEXMODE])
2151 {
2152 case WINED3DFOG_NONE: RT_FALL_THRU();
2153 case WINED3DFOG_LINEAR: args->fog = FOG_LINEAR; break;
2154 case WINED3DFOG_EXP: args->fog = FOG_EXP; break;
2155 case WINED3DFOG_EXP2: args->fog = FOG_EXP2; break;
2156 }
2157 break;
2158
2159 case WINED3DFOG_LINEAR: args->fog = FOG_LINEAR; break;
2160 case WINED3DFOG_EXP: args->fog = FOG_EXP; break;
2161 case WINED3DFOG_EXP2: args->fog = FOG_EXP2; break;
2162 }
2163 }
2164 else
2165 {
2166 args->fog = FOG_OFF;
2167 }
2168 }
2169}
2170
2171static void pixelshader_set_limits(IWineD3DPixelShaderImpl *shader)
2172{
2173 DWORD shader_version = WINED3D_SHADER_VERSION(shader->baseShader.reg_maps.shader_version.major,
2174 shader->baseShader.reg_maps.shader_version.minor);
2175
2176 shader->baseShader.limits.attributes = 0;
2177 shader->baseShader.limits.address = 0;
2178 shader->baseShader.limits.packed_output = 0;
2179
2180 switch (shader_version)
2181 {
2182 case WINED3D_SHADER_VERSION(1, 0):
2183 case WINED3D_SHADER_VERSION(1, 1):
2184 case WINED3D_SHADER_VERSION(1, 2):
2185 case WINED3D_SHADER_VERSION(1, 3):
2186 shader->baseShader.limits.temporary = 2;
2187 shader->baseShader.limits.constant_float = 8;
2188 shader->baseShader.limits.constant_int = 0;
2189 shader->baseShader.limits.constant_bool = 0;
2190 shader->baseShader.limits.texcoord = 4;
2191 shader->baseShader.limits.sampler = 4;
2192 shader->baseShader.limits.packed_input = 0;
2193 shader->baseShader.limits.label = 0;
2194 break;
2195
2196 case WINED3D_SHADER_VERSION(1, 4):
2197 shader->baseShader.limits.temporary = 6;
2198 shader->baseShader.limits.constant_float = 8;
2199 shader->baseShader.limits.constant_int = 0;
2200 shader->baseShader.limits.constant_bool = 0;
2201 shader->baseShader.limits.texcoord = 6;
2202 shader->baseShader.limits.sampler = 6;
2203 shader->baseShader.limits.packed_input = 0;
2204 shader->baseShader.limits.label = 0;
2205 break;
2206
2207 /* FIXME: Temporaries must match D3DPSHADERCAPS2_0.NumTemps. */
2208 case WINED3D_SHADER_VERSION(2, 0):
2209 shader->baseShader.limits.temporary = 32;
2210 shader->baseShader.limits.constant_float = 32;
2211 shader->baseShader.limits.constant_int = 16;
2212 shader->baseShader.limits.constant_bool = 16;
2213 shader->baseShader.limits.texcoord = 8;
2214 shader->baseShader.limits.sampler = 16;
2215 shader->baseShader.limits.packed_input = 0;
2216 break;
2217
2218 case WINED3D_SHADER_VERSION(2, 1):
2219 shader->baseShader.limits.temporary = 32;
2220 shader->baseShader.limits.constant_float = 32;
2221 shader->baseShader.limits.constant_int = 16;
2222 shader->baseShader.limits.constant_bool = 16;
2223 shader->baseShader.limits.texcoord = 8;
2224 shader->baseShader.limits.sampler = 16;
2225 shader->baseShader.limits.packed_input = 0;
2226 shader->baseShader.limits.label = 16;
2227 break;
2228
2229 case WINED3D_SHADER_VERSION(4, 0):
2230 FIXME("Using 3.0 limits for 4.0 shader.\n");
2231 RT_FALL_THRU();
2232
2233 case WINED3D_SHADER_VERSION(3, 0):
2234 shader->baseShader.limits.temporary = 32;
2235 shader->baseShader.limits.constant_float = 224;
2236 shader->baseShader.limits.constant_int = 16;
2237 shader->baseShader.limits.constant_bool = 16;
2238 shader->baseShader.limits.texcoord = 0;
2239 shader->baseShader.limits.sampler = 16;
2240 shader->baseShader.limits.packed_input = 12;
2241 shader->baseShader.limits.label = 16; /* FIXME: 2048 */
2242 break;
2243
2244 default:
2245 shader->baseShader.limits.temporary = 32;
2246 shader->baseShader.limits.constant_float = 32;
2247 shader->baseShader.limits.constant_int = 16;
2248 shader->baseShader.limits.constant_bool = 16;
2249 shader->baseShader.limits.texcoord = 8;
2250 shader->baseShader.limits.sampler = 16;
2251 shader->baseShader.limits.packed_input = 0;
2252 shader->baseShader.limits.label = 0;
2253 FIXME("Unrecognized pixel shader version %u.%u\n",
2254 shader->baseShader.reg_maps.shader_version.major,
2255 shader->baseShader.reg_maps.shader_version.minor);
2256 }
2257}
2258
2259HRESULT pixelshader_init(IWineD3DPixelShaderImpl *shader, IWineD3DDeviceImpl *device,
2260 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
2261 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
2262{
2263 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2264 unsigned int i, highest_reg_used = 0, num_regs_used = 0;
2265 HRESULT hr;
2266
2267 if (!byte_code) return WINED3DERR_INVALIDCALL;
2268
2269 shader->lpVtbl = &IWineD3DPixelShader_Vtbl;
2270 shader_init(&shader->baseShader, device, parent, parent_ops);
2271
2272 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code,
2273 output_signature, device->d3d_pshader_constantF);
2274 if (FAILED(hr))
2275 {
2276 WARN("Failed to set function, hr %#x.\n", hr);
2277 shader_cleanup((IWineD3DBaseShader *)shader);
2278 return hr;
2279 }
2280
2281 pixelshader_set_limits(shader);
2282
2283 for (i = 0; i < MAX_REG_INPUT; ++i)
2284 {
2285 if (shader->input_reg_used[i])
2286 {
2287 ++num_regs_used;
2288 highest_reg_used = i;
2289 }
2290 }
2291
2292 /* Don't do any register mapping magic if it is not needed, or if we can't
2293 * achieve anything anyway */
2294 if (highest_reg_used < (gl_info->limits.glsl_varyings / 4)
2295 || num_regs_used > (gl_info->limits.glsl_varyings / 4))
2296 {
2297 if (num_regs_used > (gl_info->limits.glsl_varyings / 4))
2298 {
2299 /* This happens with relative addressing. The input mapper function
2300 * warns about this if the higher registers are declared too, so
2301 * don't write a FIXME here */
2302 WARN("More varying registers used than supported\n");
2303 }
2304
2305 for (i = 0; i < MAX_REG_INPUT; ++i)
2306 {
2307 shader->input_reg_map[i] = i;
2308 }
2309
2310 shader->declared_in_count = highest_reg_used + 1;
2311 }
2312 else
2313 {
2314 shader->declared_in_count = 0;
2315 for (i = 0; i < MAX_REG_INPUT; ++i)
2316 {
2317 if (shader->input_reg_used[i]) shader->input_reg_map[i] = shader->declared_in_count++;
2318 else shader->input_reg_map[i] = ~0U;
2319 }
2320 }
2321
2322 shader->baseShader.load_local_constsF = FALSE;
2323
2324 return WINED3D_OK;
2325}
2326
2327void pixelshader_update_samplers(struct shader_reg_maps *reg_maps, IWineD3DBaseTexture * const *textures)
2328{
2329 WINED3DSAMPLER_TEXTURE_TYPE *sampler_type = reg_maps->sampler_type;
2330 unsigned int i;
2331
2332 if (reg_maps->shader_version.major != 1) return;
2333
2334 for (i = 0; i < max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS); ++i)
2335 {
2336 /* We don't sample from this sampler. */
2337 if (!sampler_type[i]) continue;
2338
2339 if (!textures[i])
2340 {
2341 WARN("No texture bound to sampler %u, using 2D.\n", i);
2342 sampler_type[i] = WINED3DSTT_2D;
2343 continue;
2344 }
2345
2346 switch (IWineD3DBaseTexture_GetTextureDimensions(textures[i]))
2347 {
2348 case GL_TEXTURE_RECTANGLE_ARB:
2349 case GL_TEXTURE_2D:
2350 /* We have to select between texture rectangles and 2D
2351 * textures later because 2.0 and 3.0 shaders only have
2352 * WINED3DSTT_2D as well. */
2353 sampler_type[i] = WINED3DSTT_2D;
2354 break;
2355
2356 case GL_TEXTURE_3D:
2357 sampler_type[i] = WINED3DSTT_VOLUME;
2358 break;
2359
2360 case GL_TEXTURE_CUBE_MAP_ARB:
2361 sampler_type[i] = WINED3DSTT_CUBE;
2362 break;
2363
2364 default:
2365 FIXME("Unrecognized texture type %#x, using 2D.\n",
2366 IWineD3DBaseTexture_GetTextureDimensions(textures[i]));
2367 sampler_type[i] = WINED3DSTT_2D;
2368 }
2369 }
2370}
2371
2372#ifdef VBOX_WINE_WITH_SHADER_CACHE
2373
2374static void shader_reinit(struct IWineD3DBaseShaderClass *shader, IWineD3DDeviceImpl *device,
2375 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
2376{
2377 shader->ref = 1;
2378 shader->device = (IWineD3DDevice *)device;
2379 shader->parent = parent;
2380 shader->parent_ops = parent_ops;
2381#ifdef DEBUG
2382 {
2383 IWineD3DBaseShaderImpl *tstShader;
2384 LIST_FOR_EACH_ENTRY(tstShader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
2385 if (&tstShader->baseShader == shader)
2386 return;
2387 }
2388 ERR("shader not in list!");
2389 }
2390#endif
2391}
2392
2393static DECLCALLBACK(uint32_t) shader_cache_hash(void *pvKey)
2394{
2395 uint32_t u32Hash, i;
2396 DWORD *function;
2397 IWineD3DBaseShaderImpl *pShader = (IWineD3DBaseShaderImpl *)pvKey;
2398 if (pShader->baseShader.u32CacheDataInited)
2399 return pShader->baseShader.u32Hash;
2400
2401 u32Hash = pShader->baseShader.functionLength;
2402 function = pShader->baseShader.function;
2403 for (i = 0; i < pShader->baseShader.functionLength / 4; ++i)
2404 {
2405 u32Hash += *function++;
2406 }
2407
2408 for (i = 0; i < pShader->baseShader.functionLength % 4; ++i)
2409 {
2410 u32Hash += *((uint8_t*)function)++;
2411 }
2412
2413 pShader->baseShader.u32Hash = u32Hash;
2414 pShader->baseShader.u32CacheDataInited = TRUE;
2415 return pShader->baseShader.u32Hash;
2416}
2417
2418static DECLCALLBACK(bool) shader_cache_equal(void *pvKey1, void *pvKey2)
2419{
2420 IWineD3DBaseShaderImpl *pShader1 = (IWineD3DBaseShaderImpl *)pvKey1;
2421 IWineD3DBaseShaderImpl *pShader2 = (IWineD3DBaseShaderImpl *)pvKey2;
2422
2423 if (pShader1 == pShader2)
2424 return TRUE;
2425
2426 if (pShader1->baseShader.functionLength != pShader2->baseShader.functionLength)
2427 return FALSE;
2428
2429 if (shader_cache_hash(pvKey1) != shader_cache_hash(pvKey2))
2430 {
2431#ifdef DEBUG_misha
2432 Assert(memcmp(pShader1->baseShader.function, pShader2->baseShader.function, pShader1->baseShader.functionLength));
2433#endif
2434 return FALSE;
2435 }
2436
2437 return !memcmp(pShader1->baseShader.function, pShader2->baseShader.function, pShader1->baseShader.functionLength);
2438}
2439
2440#define VBOX_SHADER_FROM_CACHE_ENTRY(_pEntry) RT_FROM_MEMBER(RT_FROM_MEMBER((_pEntry), IWineD3DBaseShaderClass, CacheEntry), IWineD3DBaseShaderImpl, baseShader)
2441
2442static DECLCALLBACK(void) shader_cache_cleanup_entry(void *pvKey, struct VBOXEXT_HASHCACHE_ENTRY *pEntry)
2443{
2444 IWineD3DBaseShaderImpl *pShader = VBOX_SHADER_FROM_CACHE_ENTRY(pEntry);
2445 shader_cleanup((IWineD3DBaseShader *)pShader);
2446 if (pShader->baseShader.parent)
2447 pShader->baseShader.parent_ops->wined3d_object_destroyed(pShader->baseShader.parent);
2448 HeapFree(GetProcessHeap(), 0, pShader);
2449}
2450
2451static void shader_chache_init(PVBOXEXT_HASHCACHE pCache)
2452{
2453 VBoxExtCacheInit(pCache, 1024, shader_cache_hash, shader_cache_equal, shader_cache_cleanup_entry);
2454}
2455
2456static void shader_chache_term(PVBOXEXT_HASHCACHE pCache)
2457{
2458 VBoxExtCacheTerm(pCache);
2459}
2460
2461static void shader_chache_put(PVBOXEXT_HASHCACHE pCache, IWineD3DBaseShaderImpl *pShader)
2462{
2463 if (pShader->baseShader.parent)
2464 {
2465 pShader->baseShader.parent_ops->wined3d_object_destroyed(pShader->baseShader.parent);
2466 pShader->baseShader.parent = NULL;
2467 }
2468
2469 VBoxExtCachePut(pCache, pShader, &pShader->baseShader.CacheEntry);
2470}
2471
2472static IWineD3DBaseShaderImpl* shader_chache_get(PVBOXEXT_HASHCACHE pCache, IWineD3DBaseShaderImpl *pShader)
2473{
2474 PVBOXEXT_HASHCACHE_ENTRY pEntry = VBoxExtCacheGet(pCache, pShader);
2475 IWineD3DBaseShaderImpl *pCachedShader;
2476
2477 if (!pEntry)
2478 return pShader;
2479
2480 pCachedShader = VBOX_SHADER_FROM_CACHE_ENTRY(pEntry);
2481 shader_reinit(&pCachedShader->baseShader, (IWineD3DDeviceImpl *)pShader->baseShader.device,
2482 pShader->baseShader.parent, pShader->baseShader.parent_ops);
2483 pShader->baseShader.parent = NULL;
2484 /* we can not do a IWineD3DBaseShader_Release here since this would result in putting a shader to the cache */
2485 shader_cleanup((IWineD3DBaseShader *)pShader);
2486 HeapFree(GetProcessHeap(), 0, pShader);
2487 return pCachedShader;
2488}
2489
2490IWineD3DVertexShaderImpl * vertexshader_check_cached(IWineD3DDeviceImpl *device, IWineD3DVertexShaderImpl *object)
2491{
2492 return (IWineD3DVertexShaderImpl*)shader_chache_get(&device->vshaderCache, (IWineD3DBaseShaderImpl *)object);
2493}
2494
2495IWineD3DPixelShaderImpl * pixelshader_check_cached(IWineD3DDeviceImpl *device, IWineD3DPixelShaderImpl *object)
2496{
2497 return (IWineD3DPixelShaderImpl*)shader_chache_get(&device->pshaderCache, (IWineD3DBaseShaderImpl *)object);
2498}
2499
2500void shader_chaches_init(IWineD3DDeviceImpl *device)
2501{
2502 shader_chache_init(&device->vshaderCache);
2503 shader_chache_init(&device->pshaderCache);
2504}
2505
2506void shader_chaches_term(IWineD3DDeviceImpl *device)
2507{
2508 shader_chache_term(&device->vshaderCache);
2509 shader_chache_term(&device->pshaderCache);
2510}
2511#endif
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette