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
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.
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.
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
30 #include "wined3d_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader
);
34 static void shader_get_parent(IWineD3DBaseShaderImpl
*shader
, IUnknown
**parent
)
36 *parent
= shader
->baseShader
.parent
;
37 IUnknown_AddRef(*parent
);
38 TRACE("shader %p, returning %p.\n", shader
, *parent
);
41 static HRESULT
shader_get_function(IWineD3DBaseShaderImpl
*shader
, void *data
, UINT
*data_size
)
45 *data_size
= shader
->baseShader
.functionLength
;
49 if (*data_size
< shader
->baseShader
.functionLength
)
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
;
57 memcpy(data
, shader
->baseShader
.function
, shader
->baseShader
.functionLength
);
62 static HRESULT STDMETHODCALLTYPE
vertexshader_QueryInterface(IWineD3DVertexShader
*iface
, REFIID riid
, void **object
)
64 TRACE("iface %p, riid %s, object %p.\n", iface
, debugstr_guid(riid
), object
);
66 if (IsEqualGUID(riid
, &IID_IWineD3DVertexShader
)
67 || IsEqualGUID(riid
, &IID_IWineD3DBaseShader
)
68 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
69 || IsEqualGUID(riid
, &IID_IUnknown
))
71 IUnknown_AddRef(iface
);
76 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid
));
82 static ULONG STDMETHODCALLTYPE
vertexshader_AddRef(IWineD3DVertexShader
*iface
)
84 IWineD3DVertexShaderImpl
*shader
= (IWineD3DVertexShaderImpl
*)iface
;
85 ULONG refcount
= InterlockedIncrement(&shader
->baseShader
.ref
);
87 TRACE("%p increasing refcount to %u.\n", shader
, refcount
);
92 static ULONG STDMETHODCALLTYPE
vertexshader_Release(IWineD3DVertexShader
*iface
)
94 IWineD3DVertexShaderImpl
*shader
= (IWineD3DVertexShaderImpl
*)iface
;
95 ULONG refcount
= InterlockedDecrement(&shader
->baseShader
.ref
);
97 TRACE("%p decreasing refcount to %u.\n", shader
, refcount
);
101 shader_cleanup((IWineD3DBaseShader
*)iface
);
102 shader
->baseShader
.parent_ops
->wined3d_object_destroyed(shader
->baseShader
.parent
);
103 HeapFree(GetProcessHeap(), 0, shader
);
109 static HRESULT STDMETHODCALLTYPE
vertexshader_GetParent(IWineD3DVertexShader
*iface
, IUnknown
**parent
)
111 TRACE("iface %p, parent %p.\n", iface
, parent
);
113 shader_get_parent((IWineD3DBaseShaderImpl
*)iface
, parent
);
118 static HRESULT STDMETHODCALLTYPE
vertexshader_GetFunction(IWineD3DVertexShader
*iface
, void *data
, UINT
*data_size
)
120 TRACE("iface %p, data %p, data_size %p.\n", iface
, data
, data_size
);
122 return shader_get_function((IWineD3DBaseShaderImpl
*)iface
, data
, data_size
);
125 /* Set local constants for d3d8 shaders. */
126 static HRESULT STDMETHODCALLTYPE
vertexshader_SetLocalConstantsF(IWineD3DVertexShader
*iface
,
127 UINT start_idx
, const float *src_data
, UINT count
)
129 IWineD3DVertexShaderImpl
*shader
=(IWineD3DVertexShaderImpl
*)iface
;
130 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)shader
->baseShader
.device
;
133 TRACE("iface %p, start_idx %u, src_data %p, count %u.\n", iface
, start_idx
, src_data
, count
);
135 end_idx
= start_idx
+ count
;
136 if (end_idx
> device
->d3d_vshader_constantF
)
138 WARN("end_idx %u > float constants limit %u.\n", end_idx
, device
->d3d_vshader_constantF
);
139 end_idx
= device
->d3d_vshader_constantF
;
142 for (i
= start_idx
; i
< end_idx
; ++i
)
144 local_constant
* lconst
= HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant
));
145 if (!lconst
) return E_OUTOFMEMORY
;
148 memcpy(lconst
->value
, src_data
+ (i
- start_idx
) * 4 /* 4 components */, 4 * sizeof(float));
149 list_add_head(&shader
->baseShader
.constantsF
, &lconst
->entry
);
155 static const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl
=
157 /* IUnknown methods */
158 vertexshader_QueryInterface
,
160 vertexshader_Release
,
161 /* IWineD3DBase methods */
162 vertexshader_GetParent
,
163 /* IWineD3DBaseShader methods */
164 vertexshader_GetFunction
,
165 /* IWineD3DVertexShader methods */
166 vertexshader_SetLocalConstantsF
,
169 void find_vs_compile_args(IWineD3DVertexShaderImpl
*shader
,
170 IWineD3DStateBlockImpl
*stateblock
, struct vs_compile_args
*args
)
172 args
->fog_src
= stateblock
->renderState
[WINED3DRS_FOGTABLEMODE
] == WINED3DFOG_NONE
? VS_FOG_COORD
: VS_FOG_Z
;
173 args
->clip_enabled
= stateblock
->renderState
[WINED3DRS_CLIPPING
]
174 && stateblock
->renderState
[WINED3DRS_CLIPPLANEENABLE
];
175 args
->swizzle_map
= ((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->strided_streams
.swizzle_map
;
178 static BOOL
match_usage(BYTE usage1
, BYTE usage_idx1
, BYTE usage2
, BYTE usage_idx2
)
180 if (usage_idx1
!= usage_idx2
) return FALSE
;
181 if (usage1
== usage2
) return TRUE
;
182 if (usage1
== WINED3DDECLUSAGE_POSITION
&& usage2
== WINED3DDECLUSAGE_POSITIONT
) return TRUE
;
183 if (usage2
== WINED3DDECLUSAGE_POSITION
&& usage1
== WINED3DDECLUSAGE_POSITIONT
) return TRUE
;
188 BOOL
vshader_get_input(IWineD3DVertexShader
*iface
, BYTE usage_req
, BYTE usage_idx_req
, unsigned int *regnum
)
190 IWineD3DVertexShaderImpl
*shader
= (IWineD3DVertexShaderImpl
*)iface
;
191 WORD map
= shader
->baseShader
.reg_maps
.input_registers
;
194 for (i
= 0; map
; map
>>= 1, ++i
)
196 if (!(map
& 1)) continue;
198 if (match_usage(shader
->attributes
[i
].usage
,
199 shader
->attributes
[i
].usage_idx
, usage_req
, usage_idx_req
))
208 static void vertexshader_set_limits(IWineD3DVertexShaderImpl
*shader
)
210 DWORD shader_version
= WINED3D_SHADER_VERSION(shader
->baseShader
.reg_maps
.shader_version
.major
,
211 shader
->baseShader
.reg_maps
.shader_version
.minor
);
212 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)shader
->baseShader
.device
;
214 shader
->baseShader
.limits
.texcoord
= 0;
215 shader
->baseShader
.limits
.attributes
= 16;
216 shader
->baseShader
.limits
.packed_input
= 0;
218 switch (shader_version
)
220 case WINED3D_SHADER_VERSION(1, 0):
221 case WINED3D_SHADER_VERSION(1, 1):
222 shader
->baseShader
.limits
.temporary
= 12;
223 shader
->baseShader
.limits
.constant_bool
= 0;
224 shader
->baseShader
.limits
.constant_int
= 0;
225 shader
->baseShader
.limits
.address
= 1;
226 shader
->baseShader
.limits
.packed_output
= 0;
227 shader
->baseShader
.limits
.sampler
= 0;
228 shader
->baseShader
.limits
.label
= 0;
229 /* TODO: vs_1_1 has a minimum of 96 constants. What happens when
230 * a vs_1_1 shader is used on a vs_3_0 capable card that has 256
232 shader
->baseShader
.limits
.constant_float
= min(256, device
->d3d_vshader_constantF
);
235 case WINED3D_SHADER_VERSION(2, 0):
236 case WINED3D_SHADER_VERSION(2, 1):
237 shader
->baseShader
.limits
.temporary
= 12;
238 shader
->baseShader
.limits
.constant_bool
= 16;
239 shader
->baseShader
.limits
.constant_int
= 16;
240 shader
->baseShader
.limits
.address
= 1;
241 shader
->baseShader
.limits
.packed_output
= 0;
242 shader
->baseShader
.limits
.sampler
= 0;
243 shader
->baseShader
.limits
.label
= 16;
244 shader
->baseShader
.limits
.constant_float
= min(256, device
->d3d_vshader_constantF
);
247 case WINED3D_SHADER_VERSION(4, 0):
248 FIXME("Using 3.0 limits for 4.0 shader.\n");
251 case WINED3D_SHADER_VERSION(3, 0):
252 shader
->baseShader
.limits
.temporary
= 32;
253 shader
->baseShader
.limits
.constant_bool
= 32;
254 shader
->baseShader
.limits
.constant_int
= 32;
255 shader
->baseShader
.limits
.address
= 1;
256 shader
->baseShader
.limits
.packed_output
= 12;
257 shader
->baseShader
.limits
.sampler
= 4;
258 shader
->baseShader
.limits
.label
= 16; /* FIXME: 2048 */
259 /* DX10 cards on Windows advertise a d3d9 constant limit of 256
260 * even though they are capable of supporting much more (GL
261 * drivers advertise 1024). d3d9.dll and d3d8.dll clamp the
262 * wined3d-advertised maximum. Clamp the constant limit for <= 3.0
264 shader
->baseShader
.limits
.constant_float
= min(256, device
->d3d_vshader_constantF
);
268 shader
->baseShader
.limits
.temporary
= 12;
269 shader
->baseShader
.limits
.constant_bool
= 16;
270 shader
->baseShader
.limits
.constant_int
= 16;
271 shader
->baseShader
.limits
.address
= 1;
272 shader
->baseShader
.limits
.packed_output
= 0;
273 shader
->baseShader
.limits
.sampler
= 0;
274 shader
->baseShader
.limits
.label
= 16;
275 shader
->baseShader
.limits
.constant_float
= min(256, device
->d3d_vshader_constantF
);
276 FIXME("Unrecognized vertex shader version \"%u.%u\".\n",
277 shader
->baseShader
.reg_maps
.shader_version
.major
,
278 shader
->baseShader
.reg_maps
.shader_version
.minor
);
282 static HRESULT
vertexshader_set_function(IWineD3DVertexShaderImpl
*shader
,
283 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
)
285 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)shader
->baseShader
.device
;
286 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
287 struct shader_reg_maps
*reg_maps
= &shader
->baseShader
.reg_maps
;
288 const struct wined3d_shader_frontend
*fe
;
292 TRACE("shader %p, byte_code %p, output_signature %p.\n", shader
, byte_code
, output_signature
);
294 fe
= shader_select_frontend(*byte_code
);
297 FIXME("Unable to find frontend for shader.\n");
298 return WINED3DERR_INVALIDCALL
;
300 shader
->baseShader
.frontend
= fe
;
301 shader
->baseShader
.frontend_data
= fe
->shader_init(byte_code
, output_signature
);
302 if (!shader
->baseShader
.frontend_data
)
304 FIXME("Failed to initialize frontend.\n");
305 return WINED3DERR_INVALIDCALL
;
308 /* First pass: trace shader. */
309 if (TRACE_ON(d3d_shader
)) shader_trace_init(fe
, shader
->baseShader
.frontend_data
, byte_code
);
311 /* Initialize immediate constant lists. */
312 list_init(&shader
->baseShader
.constantsF
);
313 list_init(&shader
->baseShader
.constantsB
);
314 list_init(&shader
->baseShader
.constantsI
);
316 /* Second pass: figure out registers used, semantics, etc. */
317 shader
->min_rel_offset
= device
->d3d_vshader_constantF
;
318 shader
->max_rel_offset
= 0;
319 hr
= shader_get_registers_used((IWineD3DBaseShader
*)shader
, fe
,
320 reg_maps
, shader
->attributes
, NULL
, shader
->output_signature
,
321 byte_code
, device
->d3d_vshader_constantF
);
322 if (FAILED(hr
)) return hr
;
324 if (output_signature
)
326 for (i
= 0; i
< output_signature
->element_count
; ++i
)
328 struct wined3d_shader_signature_element
*e
= &output_signature
->elements
[i
];
329 reg_maps
->output_registers
|= 1 << e
->register_idx
;
330 shader
->output_signature
[e
->register_idx
] = *e
;
334 vertexshader_set_limits(shader
);
336 if (device
->vs_selected_mode
== SHADER_ARB
337 && (gl_info
->quirks
& WINED3D_QUIRK_ARB_VS_OFFSET_LIMIT
)
338 && shader
->min_rel_offset
<= shader
->max_rel_offset
)
340 if (shader
->max_rel_offset
- shader
->min_rel_offset
> 127)
342 FIXME("The difference between the minimum and maximum relative offset is > 127.\n");
343 FIXME("Which this OpenGL implementation does not support. Try using GLSL.\n");
344 FIXME("Min: %d, Max: %d.\n", shader
->min_rel_offset
, shader
->max_rel_offset
);
346 else if (shader
->max_rel_offset
- shader
->min_rel_offset
> 63)
348 shader
->rel_offset
= shader
->min_rel_offset
+ 63;
350 else if (shader
->max_rel_offset
> 63)
352 shader
->rel_offset
= shader
->min_rel_offset
;
356 shader
->rel_offset
= 0;
359 shader
->baseShader
.load_local_constsF
= shader
->baseShader
.reg_maps
.usesrelconstF
360 && !list_empty(&shader
->baseShader
.constantsF
);
362 shader
->baseShader
.function
= HeapAlloc(GetProcessHeap(), 0, shader
->baseShader
.functionLength
);
363 if (!shader
->baseShader
.function
) return E_OUTOFMEMORY
;
364 memcpy(shader
->baseShader
.function
, byte_code
, shader
->baseShader
.functionLength
);
369 HRESULT
vertexshader_init(IWineD3DVertexShaderImpl
*shader
, IWineD3DDeviceImpl
*device
,
370 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
371 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
375 if (!byte_code
) return WINED3DERR_INVALIDCALL
;
377 shader
->lpVtbl
= &IWineD3DVertexShader_Vtbl
;
378 shader_init(&shader
->baseShader
, device
, parent
, parent_ops
);
380 hr
= vertexshader_set_function(shader
, byte_code
, output_signature
);
383 WARN("Failed to set function, hr %#x.\n", hr
);
384 shader_cleanup((IWineD3DBaseShader
*)shader
);
391 static HRESULT STDMETHODCALLTYPE
pixelshader_QueryInterface(IWineD3DPixelShader
*iface
, REFIID riid
, void **object
)
393 TRACE("iface %p, riid %s, object %p.\n", iface
, debugstr_guid(riid
), object
);
395 if (IsEqualGUID(riid
, &IID_IWineD3DPixelShader
)
396 || IsEqualGUID(riid
, &IID_IWineD3DBaseShader
)
397 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
398 || IsEqualGUID(riid
, &IID_IUnknown
))
400 IUnknown_AddRef(iface
);
405 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid
));
408 return E_NOINTERFACE
;
411 static ULONG STDMETHODCALLTYPE
pixelshader_AddRef(IWineD3DPixelShader
*iface
)
413 IWineD3DPixelShaderImpl
*shader
= (IWineD3DPixelShaderImpl
*)iface
;
414 ULONG refcount
= InterlockedIncrement(&shader
->baseShader
.ref
);
416 TRACE("%p increasing refcount to %u.\n", shader
, refcount
);
421 static ULONG STDMETHODCALLTYPE
pixelshader_Release(IWineD3DPixelShader
*iface
)
423 IWineD3DPixelShaderImpl
*shader
= (IWineD3DPixelShaderImpl
*)iface
;
424 ULONG refcount
= InterlockedDecrement(&shader
->baseShader
.ref
);
426 TRACE("%p decreasing refcount to %u.\n", shader
, refcount
);
430 shader_cleanup((IWineD3DBaseShader
*)iface
);
431 shader
->baseShader
.parent_ops
->wined3d_object_destroyed(shader
->baseShader
.parent
);
432 HeapFree(GetProcessHeap(), 0, shader
);
438 static HRESULT STDMETHODCALLTYPE
pixelshader_GetParent(IWineD3DPixelShader
*iface
, IUnknown
**parent
)
440 TRACE("iface %p, parent %p.\n", iface
, parent
);
442 shader_get_parent((IWineD3DBaseShaderImpl
*)iface
, parent
);
447 static HRESULT STDMETHODCALLTYPE
pixelshader_GetFunction(IWineD3DPixelShader
*iface
, void *data
, UINT
*data_size
)
449 TRACE("iface %p, data %p, data_size %p.\n", iface
, data
, data_size
);
451 return shader_get_function((IWineD3DBaseShaderImpl
*)iface
, data
, data_size
);
454 static const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl
=
456 /* IUnknown methods */
457 pixelshader_QueryInterface
,
460 /* IWineD3DBase methods */
461 pixelshader_GetParent
,
462 /* IWineD3DBaseShader methods */
463 pixelshader_GetFunction
466 void find_ps_compile_args(IWineD3DPixelShaderImpl
*shader
,
467 IWineD3DStateBlockImpl
*stateblock
, struct ps_compile_args
*args
)
469 IWineD3DBaseTextureImpl
*texture
;
472 memset(args
, 0, sizeof(*args
)); /* FIXME: Make sure all bits are set. */
473 args
->srgb_correction
= stateblock
->renderState
[WINED3DRS_SRGBWRITEENABLE
] ? 1 : 0;
476 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
)
478 if (!shader
->baseShader
.reg_maps
.sampler_type
[i
]) continue;
479 texture
= (IWineD3DBaseTextureImpl
*)stateblock
->textures
[i
];
482 args
->color_fixup
[i
] = COLOR_FIXUP_IDENTITY
;
485 args
->color_fixup
[i
] = texture
->resource
.format_desc
->color_fixup
;
487 /* Flag samplers that need NP2 texcoord fixup. */
488 if (!texture
->baseTexture
.pow2Matrix_identity
)
490 args
->np2_fixup
|= (1 << i
);
493 if (shader
->baseShader
.reg_maps
.shader_version
.major
>= 3)
495 if (((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->strided_streams
.position_transformed
)
497 args
->vp_mode
= pretransformed
;
499 else if (use_vs(stateblock
))
501 args
->vp_mode
= vertexshader
;
505 args
->vp_mode
= fixedfunction
;
511 args
->vp_mode
= vertexshader
;
512 if (stateblock
->renderState
[WINED3DRS_FOGENABLE
])
514 switch (stateblock
->renderState
[WINED3DRS_FOGTABLEMODE
])
516 case WINED3DFOG_NONE
:
517 if (((IWineD3DDeviceImpl
*)shader
->baseShader
.device
)->strided_streams
.position_transformed
518 || use_vs(stateblock
))
520 args
->fog
= FOG_LINEAR
;
524 switch (stateblock
->renderState
[WINED3DRS_FOGVERTEXMODE
])
526 case WINED3DFOG_NONE
: /* Fall through. */
527 case WINED3DFOG_LINEAR
: args
->fog
= FOG_LINEAR
; break;
528 case WINED3DFOG_EXP
: args
->fog
= FOG_EXP
; break;
529 case WINED3DFOG_EXP2
: args
->fog
= FOG_EXP2
; break;
533 case WINED3DFOG_LINEAR
: args
->fog
= FOG_LINEAR
; break;
534 case WINED3DFOG_EXP
: args
->fog
= FOG_EXP
; break;
535 case WINED3DFOG_EXP2
: args
->fog
= FOG_EXP2
; break;
545 static void pixelshader_set_limits(IWineD3DPixelShaderImpl
*shader
)
547 DWORD shader_version
= WINED3D_SHADER_VERSION(shader
->baseShader
.reg_maps
.shader_version
.major
,
548 shader
->baseShader
.reg_maps
.shader_version
.minor
);
550 shader
->baseShader
.limits
.attributes
= 0;
551 shader
->baseShader
.limits
.address
= 0;
552 shader
->baseShader
.limits
.packed_output
= 0;
554 switch (shader_version
)
556 case WINED3D_SHADER_VERSION(1, 0):
557 case WINED3D_SHADER_VERSION(1, 1):
558 case WINED3D_SHADER_VERSION(1, 2):
559 case WINED3D_SHADER_VERSION(1, 3):
560 shader
->baseShader
.limits
.temporary
= 2;
561 shader
->baseShader
.limits
.constant_float
= 8;
562 shader
->baseShader
.limits
.constant_int
= 0;
563 shader
->baseShader
.limits
.constant_bool
= 0;
564 shader
->baseShader
.limits
.texcoord
= 4;
565 shader
->baseShader
.limits
.sampler
= 4;
566 shader
->baseShader
.limits
.packed_input
= 0;
567 shader
->baseShader
.limits
.label
= 0;
570 case WINED3D_SHADER_VERSION(1, 4):
571 shader
->baseShader
.limits
.temporary
= 6;
572 shader
->baseShader
.limits
.constant_float
= 8;
573 shader
->baseShader
.limits
.constant_int
= 0;
574 shader
->baseShader
.limits
.constant_bool
= 0;
575 shader
->baseShader
.limits
.texcoord
= 6;
576 shader
->baseShader
.limits
.sampler
= 6;
577 shader
->baseShader
.limits
.packed_input
= 0;
578 shader
->baseShader
.limits
.label
= 0;
581 /* FIXME: Temporaries must match D3DPSHADERCAPS2_0.NumTemps. */
582 case WINED3D_SHADER_VERSION(2, 0):
583 shader
->baseShader
.limits
.temporary
= 32;
584 shader
->baseShader
.limits
.constant_float
= 32;
585 shader
->baseShader
.limits
.constant_int
= 16;
586 shader
->baseShader
.limits
.constant_bool
= 16;
587 shader
->baseShader
.limits
.texcoord
= 8;
588 shader
->baseShader
.limits
.sampler
= 16;
589 shader
->baseShader
.limits
.packed_input
= 0;
592 case WINED3D_SHADER_VERSION(2, 1):
593 shader
->baseShader
.limits
.temporary
= 32;
594 shader
->baseShader
.limits
.constant_float
= 32;
595 shader
->baseShader
.limits
.constant_int
= 16;
596 shader
->baseShader
.limits
.constant_bool
= 16;
597 shader
->baseShader
.limits
.texcoord
= 8;
598 shader
->baseShader
.limits
.sampler
= 16;
599 shader
->baseShader
.limits
.packed_input
= 0;
600 shader
->baseShader
.limits
.label
= 16;
603 case WINED3D_SHADER_VERSION(4, 0):
604 FIXME("Using 3.0 limits for 4.0 shader.\n");
607 case WINED3D_SHADER_VERSION(3, 0):
608 shader
->baseShader
.limits
.temporary
= 32;
609 shader
->baseShader
.limits
.constant_float
= 224;
610 shader
->baseShader
.limits
.constant_int
= 16;
611 shader
->baseShader
.limits
.constant_bool
= 16;
612 shader
->baseShader
.limits
.texcoord
= 0;
613 shader
->baseShader
.limits
.sampler
= 16;
614 shader
->baseShader
.limits
.packed_input
= 12;
615 shader
->baseShader
.limits
.label
= 16; /* FIXME: 2048 */
619 shader
->baseShader
.limits
.temporary
= 32;
620 shader
->baseShader
.limits
.constant_float
= 32;
621 shader
->baseShader
.limits
.constant_int
= 16;
622 shader
->baseShader
.limits
.constant_bool
= 16;
623 shader
->baseShader
.limits
.texcoord
= 8;
624 shader
->baseShader
.limits
.sampler
= 16;
625 shader
->baseShader
.limits
.packed_input
= 0;
626 shader
->baseShader
.limits
.label
= 0;
627 FIXME("Unrecognized pixel shader version %u.%u\n",
628 shader
->baseShader
.reg_maps
.shader_version
.major
,
629 shader
->baseShader
.reg_maps
.shader_version
.minor
);
633 static HRESULT
pixelshader_set_function(IWineD3DPixelShaderImpl
*shader
,
634 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
)
636 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)shader
->baseShader
.device
;
637 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
638 struct shader_reg_maps
*reg_maps
= &shader
->baseShader
.reg_maps
;
639 unsigned int i
, highest_reg_used
= 0, num_regs_used
= 0;
640 const struct wined3d_shader_frontend
*fe
;
643 TRACE("shader %p, byte_code %p, output_signature %p.\n", shader
, byte_code
, output_signature
);
645 fe
= shader_select_frontend(*byte_code
);
648 FIXME("Unable to find frontend for shader.\n");
649 return WINED3DERR_INVALIDCALL
;
651 shader
->baseShader
.frontend
= fe
;
652 shader
->baseShader
.frontend_data
= fe
->shader_init(byte_code
, output_signature
);
653 if (!shader
->baseShader
.frontend_data
)
655 FIXME("Failed to initialize frontend.\n");
656 return WINED3DERR_INVALIDCALL
;
659 /* First pass: trace shader. */
660 if (TRACE_ON(d3d_shader
)) shader_trace_init(fe
, shader
->baseShader
.frontend_data
, byte_code
);
662 /* Initialize immediate constant lists. */
663 list_init(&shader
->baseShader
.constantsF
);
664 list_init(&shader
->baseShader
.constantsB
);
665 list_init(&shader
->baseShader
.constantsI
);
667 /* Second pass: figure out which registers are used, what the semantics are, etc.. */
668 hr
= shader_get_registers_used((IWineD3DBaseShader
*)shader
, fe
,
669 reg_maps
, NULL
, shader
->input_signature
, NULL
,
670 byte_code
, device
->d3d_pshader_constantF
);
671 if (FAILED(hr
)) return hr
;
673 pixelshader_set_limits(shader
);
675 for (i
= 0; i
< MAX_REG_INPUT
; ++i
)
677 if (shader
->input_reg_used
[i
])
680 highest_reg_used
= i
;
684 /* Don't do any register mapping magic if it is not needed, or if we can't
685 * achieve anything anyway */
686 if (highest_reg_used
< (gl_info
->limits
.glsl_varyings
/ 4)
687 || num_regs_used
> (gl_info
->limits
.glsl_varyings
/ 4))
689 if (num_regs_used
> (gl_info
->limits
.glsl_varyings
/ 4))
691 /* This happens with relative addressing. The input mapper function
692 * warns about this if the higher registers are declared too, so
693 * don't write a FIXME here */
694 WARN("More varying registers used than supported\n");
697 for (i
= 0; i
< MAX_REG_INPUT
; ++i
)
699 shader
->input_reg_map
[i
] = i
;
702 shader
->declared_in_count
= highest_reg_used
+ 1;
706 shader
->declared_in_count
= 0;
707 for (i
= 0; i
< MAX_REG_INPUT
; ++i
)
709 if (shader
->input_reg_used
[i
]) shader
->input_reg_map
[i
] = shader
->declared_in_count
++;
710 else shader
->input_reg_map
[i
] = ~0U;
714 shader
->baseShader
.load_local_constsF
= FALSE
;
716 shader
->baseShader
.function
= HeapAlloc(GetProcessHeap(), 0, shader
->baseShader
.functionLength
);
717 if (!shader
->baseShader
.function
) return E_OUTOFMEMORY
;
718 memcpy(shader
->baseShader
.function
, byte_code
, shader
->baseShader
.functionLength
);
723 HRESULT
pixelshader_init(IWineD3DPixelShaderImpl
*shader
, IWineD3DDeviceImpl
*device
,
724 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
725 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
729 if (!byte_code
) return WINED3DERR_INVALIDCALL
;
731 shader
->lpVtbl
= &IWineD3DPixelShader_Vtbl
;
732 shader_init(&shader
->baseShader
, device
, parent
, parent_ops
);
734 hr
= pixelshader_set_function(shader
, byte_code
, output_signature
);
737 WARN("Failed to set function, hr %#x.\n", hr
);
738 shader_cleanup((IWineD3DBaseShader
*)shader
);
745 void pixelshader_update_samplers(struct shader_reg_maps
*reg_maps
, IWineD3DBaseTexture
* const *textures
)
747 WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
= reg_maps
->sampler_type
;
750 if (reg_maps
->shader_version
.major
!= 1) return;
752 for (i
= 0; i
< max(MAX_FRAGMENT_SAMPLERS
, MAX_VERTEX_SAMPLERS
); ++i
)
754 /* We don't sample from this sampler. */
755 if (!sampler_type
[i
]) continue;
759 WARN("No texture bound to sampler %u, using 2D.\n", i
);
760 sampler_type
[i
] = WINED3DSTT_2D
;
764 switch (IWineD3DBaseTexture_GetTextureDimensions(textures
[i
]))
766 case GL_TEXTURE_RECTANGLE_ARB
:
768 /* We have to select between texture rectangles and 2D
769 * textures later because 2.0 and 3.0 shaders only have
770 * WINED3DSTT_2D as well. */
771 sampler_type
[i
] = WINED3DSTT_2D
;
775 sampler_type
[i
] = WINED3DSTT_VOLUME
;
778 case GL_TEXTURE_CUBE_MAP_ARB
:
779 sampler_type
[i
] = WINED3DSTT_CUBE
;
783 FIXME("Unrecognized texture type %#x, using 2D.\n",
784 IWineD3DBaseTexture_GetTextureDimensions(textures
[i
]));
785 sampler_type
[i
] = WINED3DSTT_2D
;