winejoystick: Fix a crash on accessing a CFArray past its end due to an off-by-one...
[wine/multimedia.git] / dlls / d3d10core / shader.c
blob0b052c6187df61c694c91cb2492a565c646c0a38
1 /*
2 * Copyright 2009 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include "d3d10core_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d10core);
27 static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
29 struct d3d10_shader_info *shader_info = ctx;
30 HRESULT hr;
32 switch (tag)
34 case TAG_ISGN:
35 if (FAILED(hr = shader_parse_signature(data, data_size, shader_info->input_signature)))
36 return hr;
37 break;
39 case TAG_OSGN:
40 if (FAILED(hr = shader_parse_signature(data, data_size, shader_info->output_signature)))
41 return hr;
42 break;
44 case TAG_SHDR:
45 shader_info->shader_code = (const DWORD *)data;
46 break;
48 default:
49 FIXME("Unhandled chunk %s\n", debugstr_an((const char *)&tag, 4));
50 break;
53 return S_OK;
56 static HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length, struct d3d10_shader_info *shader_info)
58 HRESULT hr;
60 shader_info->shader_code = NULL;
61 memset(shader_info->input_signature, 0, sizeof(*shader_info->input_signature));
62 memset(shader_info->output_signature, 0, sizeof(*shader_info->output_signature));
64 hr = parse_dxbc(dxbc, dxbc_length, shdr_handler, shader_info);
65 if (!shader_info->shader_code) hr = E_INVALIDARG;
67 if (FAILED(hr))
69 ERR("Failed to parse shader, hr %#x\n", hr);
70 shader_free_signature(shader_info->input_signature);
71 shader_free_signature(shader_info->output_signature);
74 return hr;
77 HRESULT shader_parse_signature(const char *data, DWORD data_size, struct wined3d_shader_signature *s)
79 struct wined3d_shader_signature_element *e;
80 const char *ptr = data;
81 unsigned int i;
82 DWORD count;
84 read_dword(&ptr, &count);
85 TRACE("%u elements\n", count);
87 skip_dword_unknown(&ptr, 1);
89 e = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*e));
90 if (!e)
92 ERR("Failed to allocate input signature memory.\n");
93 return E_OUTOFMEMORY;
96 for (i = 0; i < count; ++i)
98 UINT name_offset;
100 read_dword(&ptr, &name_offset);
101 e[i].semantic_name = data + name_offset;
102 read_dword(&ptr, &e[i].semantic_idx);
103 read_dword(&ptr, &e[i].sysval_semantic);
104 read_dword(&ptr, &e[i].component_type);
105 read_dword(&ptr, &e[i].register_idx);
106 read_dword(&ptr, &e[i].mask);
108 TRACE("semantic: %s, semantic idx: %u, sysval_semantic %#x, "
109 "type %u, register idx: %u, use_mask %#x, input_mask %#x\n",
110 debugstr_a(e[i].semantic_name), e[i].semantic_idx, e[i].sysval_semantic,
111 e[i].component_type, e[i].register_idx, (e[i].mask >> 8) & 0xff, e[i].mask & 0xff);
114 s->elements = e;
115 s->element_count = count;
117 return S_OK;
120 void shader_free_signature(struct wined3d_shader_signature *s)
122 HeapFree(GetProcessHeap(), 0, s->elements);
125 static inline struct d3d10_vertex_shader *impl_from_ID3D10VertexShader(ID3D10VertexShader *iface)
127 return CONTAINING_RECORD(iface, struct d3d10_vertex_shader, ID3D10VertexShader_iface);
130 /* IUnknown methods */
132 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_QueryInterface(ID3D10VertexShader *iface,
133 REFIID riid, void **object)
135 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
137 if (IsEqualGUID(riid, &IID_ID3D10VertexShader)
138 || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
139 || IsEqualGUID(riid, &IID_IUnknown))
141 IUnknown_AddRef(iface);
142 *object = iface;
143 return S_OK;
146 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
148 *object = NULL;
149 return E_NOINTERFACE;
152 static ULONG STDMETHODCALLTYPE d3d10_vertex_shader_AddRef(ID3D10VertexShader *iface)
154 struct d3d10_vertex_shader *This = impl_from_ID3D10VertexShader(iface);
155 ULONG refcount = InterlockedIncrement(&This->refcount);
157 TRACE("%p increasing refcount to %u\n", This, refcount);
159 if (refcount == 1)
161 ID3D10Device1_AddRef(This->device);
162 wined3d_shader_incref(This->wined3d_shader);
165 return refcount;
168 static ULONG STDMETHODCALLTYPE d3d10_vertex_shader_Release(ID3D10VertexShader *iface)
170 struct d3d10_vertex_shader *This = impl_from_ID3D10VertexShader(iface);
171 ULONG refcount = InterlockedDecrement(&This->refcount);
173 TRACE("%p decreasing refcount to %u\n", This, refcount);
175 if (!refcount)
177 ID3D10Device1 *device = This->device;
179 wined3d_shader_decref(This->wined3d_shader);
180 /* Release the device last, it may cause the wined3d device to be
181 * destroyed. */
182 ID3D10Device1_Release(device);
185 return refcount;
188 /* ID3D10DeviceChild methods */
190 static void STDMETHODCALLTYPE d3d10_vertex_shader_GetDevice(ID3D10VertexShader *iface, ID3D10Device **device)
192 struct d3d10_vertex_shader *shader = impl_from_ID3D10VertexShader(iface);
194 TRACE("iface %p, device %p.\n", iface, device);
196 *device = (ID3D10Device *)shader->device;
197 ID3D10Device_AddRef(*device);
200 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_GetPrivateData(ID3D10VertexShader *iface,
201 REFGUID guid, UINT *data_size, void *data)
203 struct d3d10_vertex_shader *shader = impl_from_ID3D10VertexShader(iface);
205 TRACE("iface %p, guid %s, data_size %p, data %p.\n",
206 iface, debugstr_guid(guid), data_size, data);
208 return d3d10_get_private_data(&shader->private_store, guid, data_size, data);
211 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_SetPrivateData(ID3D10VertexShader *iface,
212 REFGUID guid, UINT data_size, const void *data)
214 struct d3d10_vertex_shader *shader = impl_from_ID3D10VertexShader(iface);
216 TRACE("iface %p, guid %s, data_size %u, data %p.\n",
217 iface, debugstr_guid(guid), data_size, data);
219 return d3d10_set_private_data(&shader->private_store, guid, data_size, data);
222 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_SetPrivateDataInterface(ID3D10VertexShader *iface,
223 REFGUID guid, const IUnknown *data)
225 struct d3d10_vertex_shader *shader = impl_from_ID3D10VertexShader(iface);
227 TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
229 return d3d10_set_private_data_interface(&shader->private_store, guid, data);
232 static const struct ID3D10VertexShaderVtbl d3d10_vertex_shader_vtbl =
234 /* IUnknown methods */
235 d3d10_vertex_shader_QueryInterface,
236 d3d10_vertex_shader_AddRef,
237 d3d10_vertex_shader_Release,
238 /* ID3D10DeviceChild methods */
239 d3d10_vertex_shader_GetDevice,
240 d3d10_vertex_shader_GetPrivateData,
241 d3d10_vertex_shader_SetPrivateData,
242 d3d10_vertex_shader_SetPrivateDataInterface,
245 static void STDMETHODCALLTYPE d3d10_vertex_shader_wined3d_object_destroyed(void *parent)
247 struct d3d10_vertex_shader *shader = parent;
249 wined3d_private_store_cleanup(&shader->private_store);
250 HeapFree(GetProcessHeap(), 0, parent);
253 static const struct wined3d_parent_ops d3d10_vertex_shader_wined3d_parent_ops =
255 d3d10_vertex_shader_wined3d_object_destroyed,
258 HRESULT d3d10_vertex_shader_init(struct d3d10_vertex_shader *shader, struct d3d10_device *device,
259 const void *byte_code, SIZE_T byte_code_length)
261 struct wined3d_shader_signature output_signature;
262 struct wined3d_shader_signature input_signature;
263 struct d3d10_shader_info shader_info;
264 struct wined3d_shader_desc desc;
265 HRESULT hr;
267 shader->ID3D10VertexShader_iface.lpVtbl = &d3d10_vertex_shader_vtbl;
268 shader->refcount = 1;
269 wined3d_private_store_init(&shader->private_store);
271 shader_info.input_signature = &input_signature;
272 shader_info.output_signature = &output_signature;
273 if (FAILED(hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info)))
275 ERR("Failed to extract shader, hr %#x.\n", hr);
276 wined3d_private_store_cleanup(&shader->private_store);
277 return hr;
280 desc.byte_code = shader_info.shader_code;
281 desc.input_signature = &input_signature;
282 desc.output_signature = &output_signature;
283 desc.max_version = 4;
285 hr = wined3d_shader_create_vs(device->wined3d_device, &desc, shader,
286 &d3d10_vertex_shader_wined3d_parent_ops, &shader->wined3d_shader);
287 shader_free_signature(&input_signature);
288 shader_free_signature(&output_signature);
289 if (FAILED(hr))
291 WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
292 wined3d_private_store_cleanup(&shader->private_store);
293 return E_INVALIDARG;
296 shader->device = &device->ID3D10Device1_iface;
297 ID3D10Device1_AddRef(shader->device);
299 return S_OK;
302 struct d3d10_vertex_shader *unsafe_impl_from_ID3D10VertexShader(ID3D10VertexShader *iface)
304 if (!iface)
305 return NULL;
306 assert(iface->lpVtbl == &d3d10_vertex_shader_vtbl);
308 return impl_from_ID3D10VertexShader(iface);
311 static inline struct d3d10_geometry_shader *impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
313 return CONTAINING_RECORD(iface, struct d3d10_geometry_shader, ID3D10GeometryShader_iface);
316 /* IUnknown methods */
318 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_QueryInterface(ID3D10GeometryShader *iface,
319 REFIID riid, void **object)
321 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
323 if (IsEqualGUID(riid, &IID_ID3D10GeometryShader)
324 || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
325 || IsEqualGUID(riid, &IID_IUnknown))
327 IUnknown_AddRef(iface);
328 *object = iface;
329 return S_OK;
332 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
334 *object = NULL;
335 return E_NOINTERFACE;
338 static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_AddRef(ID3D10GeometryShader *iface)
340 struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
341 ULONG refcount = InterlockedIncrement(&This->refcount);
343 TRACE("%p increasing refcount to %u\n", This, refcount);
345 return refcount;
348 static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_Release(ID3D10GeometryShader *iface)
350 struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
351 ULONG refcount = InterlockedDecrement(&This->refcount);
353 TRACE("%p decreasing refcount to %u\n", This, refcount);
355 if (!refcount)
356 wined3d_shader_decref(This->wined3d_shader);
358 return refcount;
361 /* ID3D10DeviceChild methods */
363 static void STDMETHODCALLTYPE d3d10_geometry_shader_GetDevice(ID3D10GeometryShader *iface, ID3D10Device **device)
365 FIXME("iface %p, device %p stub!\n", iface, device);
368 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_GetPrivateData(ID3D10GeometryShader *iface,
369 REFGUID guid, UINT *data_size, void *data)
371 struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
373 TRACE("iface %p, guid %s, data_size %p, data %p.\n",
374 iface, debugstr_guid(guid), data_size, data);
376 return d3d10_get_private_data(&shader->private_store, guid, data_size, data);
379 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateData(ID3D10GeometryShader *iface,
380 REFGUID guid, UINT data_size, const void *data)
382 struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
384 TRACE("iface %p, guid %s, data_size %u, data %p.\n",
385 iface, debugstr_guid(guid), data_size, data);
387 return d3d10_set_private_data(&shader->private_store, guid, data_size, data);
390 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateDataInterface(ID3D10GeometryShader *iface,
391 REFGUID guid, const IUnknown *data)
393 struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
395 TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
397 return d3d10_set_private_data_interface(&shader->private_store, guid, data);
400 static const struct ID3D10GeometryShaderVtbl d3d10_geometry_shader_vtbl =
402 /* IUnknown methods */
403 d3d10_geometry_shader_QueryInterface,
404 d3d10_geometry_shader_AddRef,
405 d3d10_geometry_shader_Release,
406 /* ID3D10DeviceChild methods */
407 d3d10_geometry_shader_GetDevice,
408 d3d10_geometry_shader_GetPrivateData,
409 d3d10_geometry_shader_SetPrivateData,
410 d3d10_geometry_shader_SetPrivateDataInterface,
413 static void STDMETHODCALLTYPE d3d10_geometry_shader_wined3d_object_destroyed(void *parent)
415 struct d3d10_geometry_shader *shader = parent;
417 wined3d_private_store_cleanup(&shader->private_store);
418 HeapFree(GetProcessHeap(), 0, parent);
421 static const struct wined3d_parent_ops d3d10_geometry_shader_wined3d_parent_ops =
423 d3d10_geometry_shader_wined3d_object_destroyed,
426 HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct d3d10_device *device,
427 const void *byte_code, SIZE_T byte_code_length)
429 struct wined3d_shader_signature output_signature;
430 struct wined3d_shader_signature input_signature;
431 struct d3d10_shader_info shader_info;
432 struct wined3d_shader_desc desc;
433 HRESULT hr;
435 shader->ID3D10GeometryShader_iface.lpVtbl = &d3d10_geometry_shader_vtbl;
436 shader->refcount = 1;
437 wined3d_private_store_init(&shader->private_store);
439 shader_info.input_signature = &input_signature;
440 shader_info.output_signature = &output_signature;
441 if (FAILED(hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info)))
443 ERR("Failed to extract shader, hr %#x.\n", hr);
444 wined3d_private_store_cleanup(&shader->private_store);
445 return hr;
448 desc.byte_code = shader_info.shader_code;
449 desc.input_signature = &input_signature;
450 desc.output_signature = &output_signature;
451 desc.max_version = 4;
453 hr = wined3d_shader_create_gs(device->wined3d_device, &desc, shader,
454 &d3d10_geometry_shader_wined3d_parent_ops, &shader->wined3d_shader);
455 shader_free_signature(&input_signature);
456 shader_free_signature(&output_signature);
457 if (FAILED(hr))
459 WARN("Failed to create wined3d geometry shader, hr %#x.\n", hr);
460 wined3d_private_store_cleanup(&shader->private_store);
461 return E_INVALIDARG;
464 return S_OK;
467 struct d3d10_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
469 if (!iface)
470 return NULL;
471 assert(iface->lpVtbl == &d3d10_geometry_shader_vtbl);
473 return impl_from_ID3D10GeometryShader(iface);
476 static inline struct d3d10_pixel_shader *impl_from_ID3D10PixelShader(ID3D10PixelShader *iface)
478 return CONTAINING_RECORD(iface, struct d3d10_pixel_shader, ID3D10PixelShader_iface);
481 /* IUnknown methods */
483 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_QueryInterface(ID3D10PixelShader *iface,
484 REFIID riid, void **object)
486 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
488 if (IsEqualGUID(riid, &IID_ID3D10PixelShader)
489 || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
490 || IsEqualGUID(riid, &IID_IUnknown))
492 IUnknown_AddRef(iface);
493 *object = iface;
494 return S_OK;
497 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
499 *object = NULL;
500 return E_NOINTERFACE;
503 static ULONG STDMETHODCALLTYPE d3d10_pixel_shader_AddRef(ID3D10PixelShader *iface)
505 struct d3d10_pixel_shader *This = impl_from_ID3D10PixelShader(iface);
506 ULONG refcount = InterlockedIncrement(&This->refcount);
508 TRACE("%p increasing refcount to %u\n", This, refcount);
510 if (refcount == 1)
512 ID3D10Device1_AddRef(This->device);
513 wined3d_shader_incref(This->wined3d_shader);
516 return refcount;
519 static ULONG STDMETHODCALLTYPE d3d10_pixel_shader_Release(ID3D10PixelShader *iface)
521 struct d3d10_pixel_shader *This = impl_from_ID3D10PixelShader(iface);
522 ULONG refcount = InterlockedDecrement(&This->refcount);
524 TRACE("%p decreasing refcount to %u\n", This, refcount);
526 if (!refcount)
528 ID3D10Device1 *device = This->device;
530 wined3d_shader_decref(This->wined3d_shader);
531 /* Release the device last, it may cause the wined3d device to be
532 * destroyed. */
533 ID3D10Device1_Release(device);
536 return refcount;
539 /* ID3D10DeviceChild methods */
541 static void STDMETHODCALLTYPE d3d10_pixel_shader_GetDevice(ID3D10PixelShader *iface, ID3D10Device **device)
543 struct d3d10_pixel_shader *shader = impl_from_ID3D10PixelShader(iface);
545 TRACE("iface %p, device %p.\n", iface, device);
547 *device = (ID3D10Device *)shader->device;
548 ID3D10Device_AddRef(*device);
551 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_GetPrivateData(ID3D10PixelShader *iface,
552 REFGUID guid, UINT *data_size, void *data)
554 struct d3d10_pixel_shader *shader = impl_from_ID3D10PixelShader(iface);
556 TRACE("iface %p, guid %s, data_size %p, data %p.\n",
557 iface, debugstr_guid(guid), data_size, data);
559 return d3d10_get_private_data(&shader->private_store, guid, data_size, data);
562 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_SetPrivateData(ID3D10PixelShader *iface,
563 REFGUID guid, UINT data_size, const void *data)
565 struct d3d10_pixel_shader *shader = impl_from_ID3D10PixelShader(iface);
567 TRACE("iface %p, guid %s, data_size %u, data %p.\n",
568 iface, debugstr_guid(guid), data_size, data);
570 return d3d10_set_private_data(&shader->private_store, guid, data_size, data);
573 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_SetPrivateDataInterface(ID3D10PixelShader *iface,
574 REFGUID guid, const IUnknown *data)
576 struct d3d10_pixel_shader *shader = impl_from_ID3D10PixelShader(iface);
578 TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
580 return d3d10_set_private_data_interface(&shader->private_store, guid, data);
583 static const struct ID3D10PixelShaderVtbl d3d10_pixel_shader_vtbl =
585 /* IUnknown methods */
586 d3d10_pixel_shader_QueryInterface,
587 d3d10_pixel_shader_AddRef,
588 d3d10_pixel_shader_Release,
589 /* ID3D10DeviceChild methods */
590 d3d10_pixel_shader_GetDevice,
591 d3d10_pixel_shader_GetPrivateData,
592 d3d10_pixel_shader_SetPrivateData,
593 d3d10_pixel_shader_SetPrivateDataInterface,
596 static void STDMETHODCALLTYPE d3d10_pixel_shader_wined3d_object_destroyed(void *parent)
598 struct d3d10_pixel_shader *shader = parent;
600 wined3d_private_store_cleanup(&shader->private_store);
601 HeapFree(GetProcessHeap(), 0, parent);
604 static const struct wined3d_parent_ops d3d10_pixel_shader_wined3d_parent_ops =
606 d3d10_pixel_shader_wined3d_object_destroyed,
609 HRESULT d3d10_pixel_shader_init(struct d3d10_pixel_shader *shader, struct d3d10_device *device,
610 const void *byte_code, SIZE_T byte_code_length)
612 struct wined3d_shader_signature output_signature;
613 struct wined3d_shader_signature input_signature;
614 struct d3d10_shader_info shader_info;
615 struct wined3d_shader_desc desc;
616 HRESULT hr;
618 shader->ID3D10PixelShader_iface.lpVtbl = &d3d10_pixel_shader_vtbl;
619 shader->refcount = 1;
620 wined3d_private_store_init(&shader->private_store);
622 shader_info.input_signature = &input_signature;
623 shader_info.output_signature = &output_signature;
624 if (FAILED(hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info)))
626 ERR("Failed to extract shader, hr %#x.\n", hr);
627 wined3d_private_store_cleanup(&shader->private_store);
628 return hr;
631 desc.byte_code = shader_info.shader_code;
632 desc.input_signature = &input_signature;
633 desc.output_signature = &output_signature;
634 desc.max_version = 4;
636 hr = wined3d_shader_create_ps(device->wined3d_device, &desc, shader,
637 &d3d10_pixel_shader_wined3d_parent_ops, &shader->wined3d_shader);
638 shader_free_signature(&input_signature);
639 shader_free_signature(&output_signature);
640 if (FAILED(hr))
642 WARN("Failed to create wined3d pixel shader, hr %#x.\n", hr);
643 wined3d_private_store_cleanup(&shader->private_store);
644 return E_INVALIDARG;
647 shader->device = &device->ID3D10Device1_iface;
648 ID3D10Device1_AddRef(shader->device);
650 return S_OK;
653 struct d3d10_pixel_shader *unsafe_impl_from_ID3D10PixelShader(ID3D10PixelShader *iface)
655 if (!iface)
656 return NULL;
657 assert(iface->lpVtbl == &d3d10_pixel_shader_vtbl);
659 return impl_from_ID3D10PixelShader(iface);