- Merge from trunk up to r45543
[reactos.git] / dll / directx / wine / wined3d / shader.c
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 #include "config.h"
26
27 #include <math.h>
28 #include <stdio.h>
29
30 #include "wined3d_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
33
34 static void shader_get_parent(IWineD3DBaseShaderImpl *shader, IUnknown **parent)
35 {
36 *parent = shader->baseShader.parent;
37 IUnknown_AddRef(*parent);
38 TRACE("shader %p, returning %p.\n", shader, *parent);
39 }
40
41 static HRESULT shader_get_function(IWineD3DBaseShaderImpl *shader, void *data, UINT *data_size)
42 {
43 if (!data)
44 {
45 *data_size = shader->baseShader.functionLength;
46 return WINED3D_OK;
47 }
48
49 if (*data_size < shader->baseShader.functionLength)
50 {
51 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
52 * than the required size we should write the required size and
53 * return D3DERR_MOREDATA. That's not actually true. */
54 return WINED3DERR_INVALIDCALL;
55 }
56
57 memcpy(data, shader->baseShader.function, shader->baseShader.functionLength);
58
59 return WINED3D_OK;
60 }
61
62 static HRESULT shader_set_function(IWineD3DBaseShaderImpl *shader, const DWORD *byte_code,
63 const struct wined3d_shader_signature *output_signature, DWORD float_const_count)
64 {
65 struct shader_reg_maps *reg_maps = &shader->baseShader.reg_maps;
66 const struct wined3d_shader_frontend *fe;
67 HRESULT hr;
68
69 TRACE("shader %p, byte_code %p, output_signature %p, float_const_count %u.\n",
70 shader, byte_code, output_signature, float_const_count);
71
72 fe = shader_select_frontend(*byte_code);
73 if (!fe)
74 {
75 FIXME("Unable to find frontend for shader.\n");
76 return WINED3DERR_INVALIDCALL;
77 }
78 shader->baseShader.frontend = fe;
79 shader->baseShader.frontend_data = fe->shader_init(byte_code, output_signature);
80 if (!shader->baseShader.frontend_data)
81 {
82 FIXME("Failed to initialize frontend.\n");
83 return WINED3DERR_INVALIDCALL;
84 }
85
86 /* First pass: trace shader. */
87 if (TRACE_ON(d3d_shader)) shader_trace_init(fe, shader->baseShader.frontend_data, byte_code);
88
89 /* Initialize immediate constant lists. */
90 list_init(&shader->baseShader.constantsF);
91 list_init(&shader->baseShader.constantsB);
92 list_init(&shader->baseShader.constantsI);
93
94 /* Second pass: figure out which registers are used, what the semantics are, etc. */
95 hr = shader_get_registers_used((IWineD3DBaseShader *)shader, fe,
96 reg_maps, shader->baseShader.input_signature, shader->baseShader.output_signature,
97 byte_code, float_const_count);
98 if (FAILED(hr)) return hr;
99
100 shader->baseShader.function = HeapAlloc(GetProcessHeap(), 0, shader->baseShader.functionLength);
101 if (!shader->baseShader.function) return E_OUTOFMEMORY;
102 memcpy(shader->baseShader.function, byte_code, shader->baseShader.functionLength);
103
104 return WINED3D_OK;
105 }
106
107 static HRESULT STDMETHODCALLTYPE vertexshader_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, void **object)
108 {
109 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
110
111 if (IsEqualGUID(riid, &IID_IWineD3DVertexShader)
112 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
113 || IsEqualGUID(riid, &IID_IWineD3DBase)
114 || IsEqualGUID(riid, &IID_IUnknown))
115 {
116 IUnknown_AddRef(iface);
117 *object = iface;
118 return S_OK;
119 }
120
121 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
122
123 *object = NULL;
124 return E_NOINTERFACE;
125 }
126
127 static ULONG STDMETHODCALLTYPE vertexshader_AddRef(IWineD3DVertexShader *iface)
128 {
129 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
130 ULONG refcount = InterlockedIncrement(&shader->baseShader.ref);
131
132 TRACE("%p increasing refcount to %u.\n", shader, refcount);
133
134 return refcount;
135 }
136
137 static ULONG STDMETHODCALLTYPE vertexshader_Release(IWineD3DVertexShader *iface)
138 {
139 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
140 ULONG refcount = InterlockedDecrement(&shader->baseShader.ref);
141
142 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
143
144 if (!refcount)
145 {
146 shader_cleanup((IWineD3DBaseShader *)iface);
147 shader->baseShader.parent_ops->wined3d_object_destroyed(shader->baseShader.parent);
148 HeapFree(GetProcessHeap(), 0, shader);
149 }
150
151 return refcount;
152 }
153
154 static HRESULT STDMETHODCALLTYPE vertexshader_GetParent(IWineD3DVertexShader *iface, IUnknown **parent)
155 {
156 TRACE("iface %p, parent %p.\n", iface, parent);
157
158 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
159
160 return WINED3D_OK;
161 }
162
163 static HRESULT STDMETHODCALLTYPE vertexshader_GetFunction(IWineD3DVertexShader *iface, void *data, UINT *data_size)
164 {
165 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
166
167 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
168 }
169
170 /* Set local constants for d3d8 shaders. */
171 static HRESULT STDMETHODCALLTYPE vertexshader_SetLocalConstantsF(IWineD3DVertexShader *iface,
172 UINT start_idx, const float *src_data, UINT count)
173 {
174 IWineD3DVertexShaderImpl *shader =(IWineD3DVertexShaderImpl *)iface;
175 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)shader->baseShader.device;
176 UINT i, end_idx;
177
178 TRACE("iface %p, start_idx %u, src_data %p, count %u.\n", iface, start_idx, src_data, count);
179
180 end_idx = start_idx + count;
181 if (end_idx > device->d3d_vshader_constantF)
182 {
183 WARN("end_idx %u > float constants limit %u.\n", end_idx, device->d3d_vshader_constantF);
184 end_idx = device->d3d_vshader_constantF;
185 }
186
187 for (i = start_idx; i < end_idx; ++i)
188 {
189 local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
190 if (!lconst) return E_OUTOFMEMORY;
191
192 lconst->idx = i;
193 memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
194 list_add_head(&shader->baseShader.constantsF, &lconst->entry);
195 }
196
197 return WINED3D_OK;
198 }
199
200 static const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
201 {
202 /* IUnknown methods */
203 vertexshader_QueryInterface,
204 vertexshader_AddRef,
205 vertexshader_Release,
206 /* IWineD3DBase methods */
207 vertexshader_GetParent,
208 /* IWineD3DBaseShader methods */
209 vertexshader_GetFunction,
210 /* IWineD3DVertexShader methods */
211 vertexshader_SetLocalConstantsF,
212 };
213
214 void find_vs_compile_args(IWineD3DVertexShaderImpl *shader,
215 IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args)
216 {
217 args->fog_src = stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE ? VS_FOG_COORD : VS_FOG_Z;
218 args->clip_enabled = stateblock->renderState[WINED3DRS_CLIPPING]
219 && stateblock->renderState[WINED3DRS_CLIPPLANEENABLE];
220 args->swizzle_map = ((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.swizzle_map;
221 }
222
223 static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2)
224 {
225 if (usage_idx1 != usage_idx2) return FALSE;
226 if (usage1 == usage2) return TRUE;
227 if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
228 if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
229
230 return FALSE;
231 }
232
233 BOOL vshader_get_input(IWineD3DVertexShader *iface, BYTE usage_req, BYTE usage_idx_req, unsigned int *regnum)
234 {
235 IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl *)iface;
236 WORD map = shader->baseShader.reg_maps.input_registers;
237 unsigned int i;
238
239 for (i = 0; map; map >>= 1, ++i)
240 {
241 if (!(map & 1)) continue;
242
243 if (match_usage(shader->attributes[i].usage,
244 shader->attributes[i].usage_idx, usage_req, usage_idx_req))
245 {
246 *regnum = i;
247 return TRUE;
248 }
249 }
250 return FALSE;
251 }
252
253 static void vertexshader_set_limits(IWineD3DVertexShaderImpl *shader)
254 {
255 DWORD shader_version = WINED3D_SHADER_VERSION(shader->baseShader.reg_maps.shader_version.major,
256 shader->baseShader.reg_maps.shader_version.minor);
257 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)shader->baseShader.device;
258
259 shader->baseShader.limits.texcoord = 0;
260 shader->baseShader.limits.attributes = 16;
261 shader->baseShader.limits.packed_input = 0;
262
263 switch (shader_version)
264 {
265 case WINED3D_SHADER_VERSION(1, 0):
266 case WINED3D_SHADER_VERSION(1, 1):
267 shader->baseShader.limits.temporary = 12;
268 shader->baseShader.limits.constant_bool = 0;
269 shader->baseShader.limits.constant_int = 0;
270 shader->baseShader.limits.address = 1;
271 shader->baseShader.limits.packed_output = 0;
272 shader->baseShader.limits.sampler = 0;
273 shader->baseShader.limits.label = 0;
274 /* TODO: vs_1_1 has a minimum of 96 constants. What happens when
275 * a vs_1_1 shader is used on a vs_3_0 capable card that has 256
276 * constants? */
277 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
278 break;
279
280 case WINED3D_SHADER_VERSION(2, 0):
281 case WINED3D_SHADER_VERSION(2, 1):
282 shader->baseShader.limits.temporary = 12;
283 shader->baseShader.limits.constant_bool = 16;
284 shader->baseShader.limits.constant_int = 16;
285 shader->baseShader.limits.address = 1;
286 shader->baseShader.limits.packed_output = 0;
287 shader->baseShader.limits.sampler = 0;
288 shader->baseShader.limits.label = 16;
289 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
290 break;
291
292 case WINED3D_SHADER_VERSION(4, 0):
293 FIXME("Using 3.0 limits for 4.0 shader.\n");
294 /* Fall through. */
295
296 case WINED3D_SHADER_VERSION(3, 0):
297 shader->baseShader.limits.temporary = 32;
298 shader->baseShader.limits.constant_bool = 32;
299 shader->baseShader.limits.constant_int = 32;
300 shader->baseShader.limits.address = 1;
301 shader->baseShader.limits.packed_output = 12;
302 shader->baseShader.limits.sampler = 4;
303 shader->baseShader.limits.label = 16; /* FIXME: 2048 */
304 /* DX10 cards on Windows advertise a d3d9 constant limit of 256
305 * even though they are capable of supporting much more (GL
306 * drivers advertise 1024). d3d9.dll and d3d8.dll clamp the
307 * wined3d-advertised maximum. Clamp the constant limit for <= 3.0
308 * shaders to 256. */
309 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
310 break;
311
312 default:
313 shader->baseShader.limits.temporary = 12;
314 shader->baseShader.limits.constant_bool = 16;
315 shader->baseShader.limits.constant_int = 16;
316 shader->baseShader.limits.address = 1;
317 shader->baseShader.limits.packed_output = 0;
318 shader->baseShader.limits.sampler = 0;
319 shader->baseShader.limits.label = 16;
320 shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
321 FIXME("Unrecognized vertex shader version \"%u.%u\".\n",
322 shader->baseShader.reg_maps.shader_version.major,
323 shader->baseShader.reg_maps.shader_version.minor);
324 }
325 }
326
327 HRESULT vertexshader_init(IWineD3DVertexShaderImpl *shader, IWineD3DDeviceImpl *device,
328 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
329 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
330 {
331 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
332 struct shader_reg_maps *reg_maps = &shader->baseShader.reg_maps;
333 unsigned int i;
334 HRESULT hr;
335 WORD map;
336
337 if (!byte_code) return WINED3DERR_INVALIDCALL;
338
339 shader->lpVtbl = &IWineD3DVertexShader_Vtbl;
340 shader_init(&shader->baseShader, device, parent, parent_ops);
341
342 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code,
343 output_signature, device->d3d_vshader_constantF);
344 if (FAILED(hr))
345 {
346 WARN("Failed to set function, hr %#x.\n", hr);
347 shader_cleanup((IWineD3DBaseShader *)shader);
348 return hr;
349 }
350
351 map = shader->baseShader.reg_maps.input_registers;
352 for (i = 0; map; map >>= 1, ++i)
353 {
354 if (!(map & 1) || !shader->baseShader.input_signature[i].semantic_name) continue;
355
356 shader->attributes[i].usage =
357 shader_usage_from_semantic_name(shader->baseShader.input_signature[i].semantic_name);
358 shader->attributes[i].usage_idx = shader->baseShader.input_signature[i].semantic_idx;
359 }
360
361 if (output_signature)
362 {
363 for (i = 0; i < output_signature->element_count; ++i)
364 {
365 struct wined3d_shader_signature_element *e = &output_signature->elements[i];
366 reg_maps->output_registers |= 1 << e->register_idx;
367 shader->baseShader.output_signature[e->register_idx] = *e;
368 }
369 }
370
371 vertexshader_set_limits(shader);
372
373 if (device->vs_selected_mode == SHADER_ARB
374 && (gl_info->quirks & WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT)
375 && shader->min_rel_offset <= shader->max_rel_offset)
376 {
377 if (shader->max_rel_offset - shader->min_rel_offset > 127)
378 {
379 FIXME("The difference between the minimum and maximum relative offset is > 127.\n");
380 FIXME("Which this OpenGL implementation does not support. Try using GLSL.\n");
381 FIXME("Min: %d, Max: %d.\n", shader->min_rel_offset, shader->max_rel_offset);
382 }
383 else if (shader->max_rel_offset - shader->min_rel_offset > 63)
384 {
385 shader->rel_offset = shader->min_rel_offset + 63;
386 }
387 else if (shader->max_rel_offset > 63)
388 {
389 shader->rel_offset = shader->min_rel_offset;
390 }
391 else
392 {
393 shader->rel_offset = 0;
394 }
395 }
396
397 shader->baseShader.load_local_constsF = shader->baseShader.reg_maps.usesrelconstF
398 && !list_empty(&shader->baseShader.constantsF);
399
400 return WINED3D_OK;
401 }
402
403 static HRESULT STDMETHODCALLTYPE geometryshader_QueryInterface(IWineD3DGeometryShader *iface,
404 REFIID riid, void **object)
405 {
406 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
407
408 if (IsEqualGUID(riid, &IID_IWineD3DGeometryShader)
409 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
410 || IsEqualGUID(riid, &IID_IWineD3DBase)
411 || IsEqualGUID(riid, &IID_IUnknown))
412 {
413 IUnknown_AddRef(iface);
414 *object = iface;
415 return S_OK;
416 }
417
418 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
419
420 *object = NULL;
421 return E_NOINTERFACE;
422 }
423
424 static ULONG STDMETHODCALLTYPE geometryshader_AddRef(IWineD3DGeometryShader *iface)
425 {
426 struct wined3d_geometryshader *shader = (struct wined3d_geometryshader *)iface;
427 ULONG refcount = InterlockedIncrement(&shader->base_shader.ref);
428
429 TRACE("%p increasing refcount to %u.\n", shader, refcount);
430
431 return refcount;
432 }
433
434 static ULONG STDMETHODCALLTYPE geometryshader_Release(IWineD3DGeometryShader *iface)
435 {
436 struct wined3d_geometryshader *shader = (struct wined3d_geometryshader *)iface;
437 ULONG refcount = InterlockedDecrement(&shader->base_shader.ref);
438
439 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
440
441 if (!refcount)
442 {
443 shader_cleanup((IWineD3DBaseShader *)iface);
444 shader->base_shader.parent_ops->wined3d_object_destroyed(shader->base_shader.parent);
445 HeapFree(GetProcessHeap(), 0, shader);
446 }
447
448 return refcount;
449 }
450
451 static HRESULT STDMETHODCALLTYPE geometryshader_GetParent(IWineD3DGeometryShader *iface, IUnknown **parent)
452 {
453 TRACE("iface %p, parent %p.\n", iface, parent);
454
455 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
456
457 return WINED3D_OK;
458 }
459
460 static HRESULT STDMETHODCALLTYPE geometryshader_GetFunction(IWineD3DGeometryShader *iface, void *data, UINT *data_size)
461 {
462 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
463
464 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
465 }
466
467 static const IWineD3DGeometryShaderVtbl wined3d_geometryshader_vtbl =
468 {
469 /* IUnknown methods */
470 geometryshader_QueryInterface,
471 geometryshader_AddRef,
472 geometryshader_Release,
473 /* IWineD3DBase methods */
474 geometryshader_GetParent,
475 /* IWineD3DBaseShader methods */
476 geometryshader_GetFunction,
477 };
478
479 HRESULT geometryshader_init(struct wined3d_geometryshader *shader, IWineD3DDeviceImpl *device,
480 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
481 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
482 {
483 HRESULT hr;
484
485 shader->vtbl = &wined3d_geometryshader_vtbl;
486 shader_init(&shader->base_shader, device, parent, parent_ops);
487
488 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code, output_signature, 0);
489 if (FAILED(hr))
490 {
491 WARN("Failed to set function, hr %#x.\n", hr);
492 shader_cleanup((IWineD3DBaseShader *)shader);
493 return hr;
494 }
495
496 shader->base_shader.load_local_constsF = FALSE;
497
498 return WINED3D_OK;
499 }
500
501 static HRESULT STDMETHODCALLTYPE pixelshader_QueryInterface(IWineD3DPixelShader *iface, REFIID riid, void **object)
502 {
503 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
504
505 if (IsEqualGUID(riid, &IID_IWineD3DPixelShader)
506 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
507 || IsEqualGUID(riid, &IID_IWineD3DBase)
508 || IsEqualGUID(riid, &IID_IUnknown))
509 {
510 IUnknown_AddRef(iface);
511 *object = iface;
512 return S_OK;
513 }
514
515 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
516
517 *object = NULL;
518 return E_NOINTERFACE;
519 }
520
521 static ULONG STDMETHODCALLTYPE pixelshader_AddRef(IWineD3DPixelShader *iface)
522 {
523 IWineD3DPixelShaderImpl *shader = (IWineD3DPixelShaderImpl *)iface;
524 ULONG refcount = InterlockedIncrement(&shader->baseShader.ref);
525
526 TRACE("%p increasing refcount to %u.\n", shader, refcount);
527
528 return refcount;
529 }
530
531 static ULONG STDMETHODCALLTYPE pixelshader_Release(IWineD3DPixelShader *iface)
532 {
533 IWineD3DPixelShaderImpl *shader = (IWineD3DPixelShaderImpl *)iface;
534 ULONG refcount = InterlockedDecrement(&shader->baseShader.ref);
535
536 TRACE("%p decreasing refcount to %u.\n", shader, refcount);
537
538 if (!refcount)
539 {
540 shader_cleanup((IWineD3DBaseShader *)iface);
541 shader->baseShader.parent_ops->wined3d_object_destroyed(shader->baseShader.parent);
542 HeapFree(GetProcessHeap(), 0, shader);
543 }
544
545 return refcount;
546 }
547
548 static HRESULT STDMETHODCALLTYPE pixelshader_GetParent(IWineD3DPixelShader *iface, IUnknown **parent)
549 {
550 TRACE("iface %p, parent %p.\n", iface, parent);
551
552 shader_get_parent((IWineD3DBaseShaderImpl *)iface, parent);
553
554 return WINED3D_OK;
555 }
556
557 static HRESULT STDMETHODCALLTYPE pixelshader_GetFunction(IWineD3DPixelShader *iface, void *data, UINT *data_size)
558 {
559 TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
560
561 return shader_get_function((IWineD3DBaseShaderImpl *)iface, data, data_size);
562 }
563
564 static const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl =
565 {
566 /* IUnknown methods */
567 pixelshader_QueryInterface,
568 pixelshader_AddRef,
569 pixelshader_Release,
570 /* IWineD3DBase methods */
571 pixelshader_GetParent,
572 /* IWineD3DBaseShader methods */
573 pixelshader_GetFunction
574 };
575
576 void find_ps_compile_args(IWineD3DPixelShaderImpl *shader,
577 IWineD3DStateBlockImpl *stateblock, struct ps_compile_args *args)
578 {
579 IWineD3DBaseTextureImpl *texture;
580 UINT i;
581
582 memset(args, 0, sizeof(*args)); /* FIXME: Make sure all bits are set. */
583 args->srgb_correction = stateblock->renderState[WINED3DRS_SRGBWRITEENABLE] ? 1 : 0;
584 args->np2_fixup = 0;
585
586 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
587 {
588 if (!shader->baseShader.reg_maps.sampler_type[i]) continue;
589 texture = (IWineD3DBaseTextureImpl *)stateblock->textures[i];
590 if (!texture)
591 {
592 args->color_fixup[i] = COLOR_FIXUP_IDENTITY;
593 continue;
594 }
595 args->color_fixup[i] = texture->resource.format_desc->color_fixup;
596
597 /* Flag samplers that need NP2 texcoord fixup. */
598 if (!texture->baseTexture.pow2Matrix_identity)
599 {
600 args->np2_fixup |= (1 << i);
601 }
602 }
603 if (shader->baseShader.reg_maps.shader_version.major >= 3)
604 {
605 if (((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.position_transformed)
606 {
607 args->vp_mode = pretransformed;
608 }
609 else if (use_vs(stateblock))
610 {
611 args->vp_mode = vertexshader;
612 }
613 else
614 {
615 args->vp_mode = fixedfunction;
616 }
617 args->fog = FOG_OFF;
618 }
619 else
620 {
621 args->vp_mode = vertexshader;
622 if (stateblock->renderState[WINED3DRS_FOGENABLE])
623 {
624 switch (stateblock->renderState[WINED3DRS_FOGTABLEMODE])
625 {
626 case WINED3DFOG_NONE:
627 if (((IWineD3DDeviceImpl *)shader->baseShader.device)->strided_streams.position_transformed
628 || use_vs(stateblock))
629 {
630 args->fog = FOG_LINEAR;
631 break;
632 }
633
634 switch (stateblock->renderState[WINED3DRS_FOGVERTEXMODE])
635 {
636 case WINED3DFOG_NONE: /* Fall through. */
637 case WINED3DFOG_LINEAR: args->fog = FOG_LINEAR; break;
638 case WINED3DFOG_EXP: args->fog = FOG_EXP; break;
639 case WINED3DFOG_EXP2: args->fog = FOG_EXP2; break;
640 }
641 break;
642
643 case WINED3DFOG_LINEAR: args->fog = FOG_LINEAR; break;
644 case WINED3DFOG_EXP: args->fog = FOG_EXP; break;
645 case WINED3DFOG_EXP2: args->fog = FOG_EXP2; break;
646 }
647 }
648 else
649 {
650 args->fog = FOG_OFF;
651 }
652 }
653 }
654
655 static void pixelshader_set_limits(IWineD3DPixelShaderImpl *shader)
656 {
657 DWORD shader_version = WINED3D_SHADER_VERSION(shader->baseShader.reg_maps.shader_version.major,
658 shader->baseShader.reg_maps.shader_version.minor);
659
660 shader->baseShader.limits.attributes = 0;
661 shader->baseShader.limits.address = 0;
662 shader->baseShader.limits.packed_output = 0;
663
664 switch (shader_version)
665 {
666 case WINED3D_SHADER_VERSION(1, 0):
667 case WINED3D_SHADER_VERSION(1, 1):
668 case WINED3D_SHADER_VERSION(1, 2):
669 case WINED3D_SHADER_VERSION(1, 3):
670 shader->baseShader.limits.temporary = 2;
671 shader->baseShader.limits.constant_float = 8;
672 shader->baseShader.limits.constant_int = 0;
673 shader->baseShader.limits.constant_bool = 0;
674 shader->baseShader.limits.texcoord = 4;
675 shader->baseShader.limits.sampler = 4;
676 shader->baseShader.limits.packed_input = 0;
677 shader->baseShader.limits.label = 0;
678 break;
679
680 case WINED3D_SHADER_VERSION(1, 4):
681 shader->baseShader.limits.temporary = 6;
682 shader->baseShader.limits.constant_float = 8;
683 shader->baseShader.limits.constant_int = 0;
684 shader->baseShader.limits.constant_bool = 0;
685 shader->baseShader.limits.texcoord = 6;
686 shader->baseShader.limits.sampler = 6;
687 shader->baseShader.limits.packed_input = 0;
688 shader->baseShader.limits.label = 0;
689 break;
690
691 /* FIXME: Temporaries must match D3DPSHADERCAPS2_0.NumTemps. */
692 case WINED3D_SHADER_VERSION(2, 0):
693 shader->baseShader.limits.temporary = 32;
694 shader->baseShader.limits.constant_float = 32;
695 shader->baseShader.limits.constant_int = 16;
696 shader->baseShader.limits.constant_bool = 16;
697 shader->baseShader.limits.texcoord = 8;
698 shader->baseShader.limits.sampler = 16;
699 shader->baseShader.limits.packed_input = 0;
700 break;
701
702 case WINED3D_SHADER_VERSION(2, 1):
703 shader->baseShader.limits.temporary = 32;
704 shader->baseShader.limits.constant_float = 32;
705 shader->baseShader.limits.constant_int = 16;
706 shader->baseShader.limits.constant_bool = 16;
707 shader->baseShader.limits.texcoord = 8;
708 shader->baseShader.limits.sampler = 16;
709 shader->baseShader.limits.packed_input = 0;
710 shader->baseShader.limits.label = 16;
711 break;
712
713 case WINED3D_SHADER_VERSION(4, 0):
714 FIXME("Using 3.0 limits for 4.0 shader.\n");
715 /* Fall through. */
716
717 case WINED3D_SHADER_VERSION(3, 0):
718 shader->baseShader.limits.temporary = 32;
719 shader->baseShader.limits.constant_float = 224;
720 shader->baseShader.limits.constant_int = 16;
721 shader->baseShader.limits.constant_bool = 16;
722 shader->baseShader.limits.texcoord = 0;
723 shader->baseShader.limits.sampler = 16;
724 shader->baseShader.limits.packed_input = 12;
725 shader->baseShader.limits.label = 16; /* FIXME: 2048 */
726 break;
727
728 default:
729 shader->baseShader.limits.temporary = 32;
730 shader->baseShader.limits.constant_float = 32;
731 shader->baseShader.limits.constant_int = 16;
732 shader->baseShader.limits.constant_bool = 16;
733 shader->baseShader.limits.texcoord = 8;
734 shader->baseShader.limits.sampler = 16;
735 shader->baseShader.limits.packed_input = 0;
736 shader->baseShader.limits.label = 0;
737 FIXME("Unrecognized pixel shader version %u.%u\n",
738 shader->baseShader.reg_maps.shader_version.major,
739 shader->baseShader.reg_maps.shader_version.minor);
740 }
741 }
742
743 HRESULT pixelshader_init(IWineD3DPixelShaderImpl *shader, IWineD3DDeviceImpl *device,
744 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
745 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
746 {
747 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
748 unsigned int i, highest_reg_used = 0, num_regs_used = 0;
749 HRESULT hr;
750
751 if (!byte_code) return WINED3DERR_INVALIDCALL;
752
753 shader->lpVtbl = &IWineD3DPixelShader_Vtbl;
754 shader_init(&shader->baseShader, device, parent, parent_ops);
755
756 hr = shader_set_function((IWineD3DBaseShaderImpl *)shader, byte_code,
757 output_signature, device->d3d_pshader_constantF);
758 if (FAILED(hr))
759 {
760 WARN("Failed to set function, hr %#x.\n", hr);
761 shader_cleanup((IWineD3DBaseShader *)shader);
762 return hr;
763 }
764
765 pixelshader_set_limits(shader);
766
767 for (i = 0; i < MAX_REG_INPUT; ++i)
768 {
769 if (shader->input_reg_used[i])
770 {
771 ++num_regs_used;
772 highest_reg_used = i;
773 }
774 }
775
776 /* Don't do any register mapping magic if it is not needed, or if we can't
777 * achieve anything anyway */
778 if (highest_reg_used < (gl_info->limits.glsl_varyings / 4)
779 || num_regs_used > (gl_info->limits.glsl_varyings / 4))
780 {
781 if (num_regs_used > (gl_info->limits.glsl_varyings / 4))
782 {
783 /* This happens with relative addressing. The input mapper function
784 * warns about this if the higher registers are declared too, so
785 * don't write a FIXME here */
786 WARN("More varying registers used than supported\n");
787 }
788
789 for (i = 0; i < MAX_REG_INPUT; ++i)
790 {
791 shader->input_reg_map[i] = i;
792 }
793
794 shader->declared_in_count = highest_reg_used + 1;
795 }
796 else
797 {
798 shader->declared_in_count = 0;
799 for (i = 0; i < MAX_REG_INPUT; ++i)
800 {
801 if (shader->input_reg_used[i]) shader->input_reg_map[i] = shader->declared_in_count++;
802 else shader->input_reg_map[i] = ~0U;
803 }
804 }
805
806 shader->baseShader.load_local_constsF = FALSE;
807
808 return WINED3D_OK;
809 }
810
811 void pixelshader_update_samplers(struct shader_reg_maps *reg_maps, IWineD3DBaseTexture * const *textures)
812 {
813 WINED3DSAMPLER_TEXTURE_TYPE *sampler_type = reg_maps->sampler_type;
814 unsigned int i;
815
816 if (reg_maps->shader_version.major != 1) return;
817
818 for (i = 0; i < max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS); ++i)
819 {
820 /* We don't sample from this sampler. */
821 if (!sampler_type[i]) continue;
822
823 if (!textures[i])
824 {
825 WARN("No texture bound to sampler %u, using 2D.\n", i);
826 sampler_type[i] = WINED3DSTT_2D;
827 continue;
828 }
829
830 switch (IWineD3DBaseTexture_GetTextureDimensions(textures[i]))
831 {
832 case GL_TEXTURE_RECTANGLE_ARB:
833 case GL_TEXTURE_2D:
834 /* We have to select between texture rectangles and 2D
835 * textures later because 2.0 and 3.0 shaders only have
836 * WINED3DSTT_2D as well. */
837 sampler_type[i] = WINED3DSTT_2D;
838 break;
839
840 case GL_TEXTURE_3D:
841 sampler_type[i] = WINED3DSTT_VOLUME;
842 break;
843
844 case GL_TEXTURE_CUBE_MAP_ARB:
845 sampler_type[i] = WINED3DSTT_CUBE;
846 break;
847
848 default:
849 FIXME("Unrecognized texture type %#x, using 2D.\n",
850 IWineD3DBaseTexture_GetTextureDimensions(textures[i]));
851 sampler_type[i] = WINED3DSTT_2D;
852 }
853 }
854 }