d3d10core: Implement d3d10_rasterizer_state_GetDesc().
[wine] / dlls / d3d10core / shader.c
1 /*
2  * Copyright 2009 Henri Verbeet for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  *
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include "d3d10core_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d10core);
26
27 static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
28 {
29     struct d3d10_shader_info *shader_info = ctx;
30     HRESULT hr;
31
32     switch(tag)
33     {
34         case TAG_OSGN:
35             hr = shader_parse_signature(data, data_size, shader_info->output_signature);
36             if (FAILED(hr)) return hr;
37             break;
38
39         case TAG_SHDR:
40             shader_info->shader_code = (const DWORD *)data;
41             break;
42
43         default:
44             FIXME("Unhandled chunk %s\n", debugstr_an((const char *)&tag, 4));
45             break;
46     }
47
48     return S_OK;
49 }
50
51 static HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length, struct d3d10_shader_info *shader_info)
52 {
53     HRESULT hr;
54
55     shader_info->shader_code = NULL;
56     memset(shader_info->output_signature, 0, sizeof(*shader_info->output_signature));
57
58     hr = parse_dxbc(dxbc, dxbc_length, shdr_handler, shader_info);
59     if (!shader_info->shader_code) hr = E_INVALIDARG;
60
61     if (FAILED(hr))
62     {
63         ERR("Failed to parse shader, hr %#x\n", hr);
64         shader_free_signature(shader_info->output_signature);
65     }
66
67     return hr;
68 }
69
70 HRESULT shader_parse_signature(const char *data, DWORD data_size, struct wined3d_shader_signature *s)
71 {
72     struct wined3d_shader_signature_element *e;
73     unsigned int string_data_offset;
74     unsigned int string_data_size;
75     const char *ptr = data;
76     char *string_data;
77     unsigned int i;
78     DWORD count;
79
80     read_dword(&ptr, &count);
81     TRACE("%u elements\n", count);
82
83     skip_dword_unknown(&ptr, 1);
84
85     e = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*e));
86     if (!e)
87     {
88         ERR("Failed to allocate input signature memory.\n");
89         return E_OUTOFMEMORY;
90     }
91
92     /* 2 DWORDs for the header, 6 for each element. */
93     string_data_offset = 2 * sizeof(DWORD) + count * 6 * sizeof(DWORD);
94     string_data_size = data_size - string_data_offset;
95     string_data = HeapAlloc(GetProcessHeap(), 0, string_data_size);
96     if (!string_data)
97     {
98         ERR("Failed to allocate string data memory.\n");
99         HeapFree(GetProcessHeap(), 0, e);
100         return E_OUTOFMEMORY;
101     }
102     memcpy(string_data, data + string_data_offset, string_data_size);
103
104     for (i = 0; i < count; ++i)
105     {
106         UINT name_offset;
107
108         read_dword(&ptr, &name_offset);
109         e[i].semantic_name = string_data + (name_offset - string_data_offset);
110         read_dword(&ptr, &e[i].semantic_idx);
111         read_dword(&ptr, &e[i].sysval_semantic);
112         read_dword(&ptr, &e[i].component_type);
113         read_dword(&ptr, &e[i].register_idx);
114         read_dword(&ptr, &e[i].mask);
115
116         TRACE("semantic: %s, semantic idx: %u, sysval_semantic %#x, "
117                 "type %u, register idx: %u, use_mask %#x, input_mask %#x\n",
118                 debugstr_a(e[i].semantic_name), e[i].semantic_idx, e[i].sysval_semantic,
119                 e[i].component_type, e[i].register_idx, (e[i].mask >> 8) & 0xff, e[i].mask & 0xff);
120     }
121
122     s->elements = e;
123     s->element_count = count;
124     s->string_data = string_data;
125
126     return S_OK;
127 }
128
129 void shader_free_signature(struct wined3d_shader_signature *s)
130 {
131     HeapFree(GetProcessHeap(), 0, s->string_data);
132     HeapFree(GetProcessHeap(), 0, s->elements);
133 }
134
135 static inline struct d3d10_vertex_shader *impl_from_ID3D10VertexShader(ID3D10VertexShader *iface)
136 {
137     return CONTAINING_RECORD(iface, struct d3d10_vertex_shader, ID3D10VertexShader_iface);
138 }
139
140 /* IUnknown methods */
141
142 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_QueryInterface(ID3D10VertexShader *iface,
143         REFIID riid, void **object)
144 {
145     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
146
147     if (IsEqualGUID(riid, &IID_ID3D10VertexShader)
148             || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
149             || IsEqualGUID(riid, &IID_IUnknown))
150     {
151         IUnknown_AddRef(iface);
152         *object = iface;
153         return S_OK;
154     }
155
156     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
157
158     *object = NULL;
159     return E_NOINTERFACE;
160 }
161
162 static ULONG STDMETHODCALLTYPE d3d10_vertex_shader_AddRef(ID3D10VertexShader *iface)
163 {
164     struct d3d10_vertex_shader *This = impl_from_ID3D10VertexShader(iface);
165     ULONG refcount = InterlockedIncrement(&This->refcount);
166
167     TRACE("%p increasing refcount to %u\n", This, refcount);
168
169     if (refcount == 1)
170         wined3d_shader_incref(This->wined3d_shader);
171
172     return refcount;
173 }
174
175 static ULONG STDMETHODCALLTYPE d3d10_vertex_shader_Release(ID3D10VertexShader *iface)
176 {
177     struct d3d10_vertex_shader *This = impl_from_ID3D10VertexShader(iface);
178     ULONG refcount = InterlockedDecrement(&This->refcount);
179
180     TRACE("%p decreasing refcount to %u\n", This, refcount);
181
182     if (!refcount)
183         wined3d_shader_decref(This->wined3d_shader);
184
185     return refcount;
186 }
187
188 /* ID3D10DeviceChild methods */
189
190 static void STDMETHODCALLTYPE d3d10_vertex_shader_GetDevice(ID3D10VertexShader *iface, ID3D10Device **device)
191 {
192     FIXME("iface %p, device %p stub!\n", iface, device);
193 }
194
195 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_GetPrivateData(ID3D10VertexShader *iface,
196         REFGUID guid, UINT *data_size, void *data)
197 {
198     FIXME("iface %p, guid %s, data_size %p, data %p stub!\n",
199             iface, debugstr_guid(guid), data_size, data);
200
201     return E_NOTIMPL;
202 }
203
204 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_SetPrivateData(ID3D10VertexShader *iface,
205         REFGUID guid, UINT data_size, const void *data)
206 {
207     FIXME("iface %p, guid %s, data_size %u, data %p stub!\n",
208             iface, debugstr_guid(guid), data_size, data);
209
210     return E_NOTIMPL;
211 }
212
213 static HRESULT STDMETHODCALLTYPE d3d10_vertex_shader_SetPrivateDataInterface(ID3D10VertexShader *iface,
214         REFGUID guid, const IUnknown *data)
215 {
216     FIXME("iface %p, guid %s, data %p stub!\n", iface, debugstr_guid(guid), data);
217
218     return E_NOTIMPL;
219 }
220
221 static const struct ID3D10VertexShaderVtbl d3d10_vertex_shader_vtbl =
222 {
223     /* IUnknown methods */
224     d3d10_vertex_shader_QueryInterface,
225     d3d10_vertex_shader_AddRef,
226     d3d10_vertex_shader_Release,
227     /* ID3D10DeviceChild methods */
228     d3d10_vertex_shader_GetDevice,
229     d3d10_vertex_shader_GetPrivateData,
230     d3d10_vertex_shader_SetPrivateData,
231     d3d10_vertex_shader_SetPrivateDataInterface,
232 };
233
234 static void STDMETHODCALLTYPE d3d10_vertex_shader_wined3d_object_destroyed(void *parent)
235 {
236     struct d3d10_vertex_shader *shader = parent;
237     shader_free_signature(&shader->output_signature);
238     HeapFree(GetProcessHeap(), 0, shader);
239 }
240
241 static const struct wined3d_parent_ops d3d10_vertex_shader_wined3d_parent_ops =
242 {
243     d3d10_vertex_shader_wined3d_object_destroyed,
244 };
245
246 HRESULT d3d10_vertex_shader_init(struct d3d10_vertex_shader *shader, struct d3d10_device *device,
247         const void *byte_code, SIZE_T byte_code_length)
248 {
249     struct d3d10_shader_info shader_info;
250     HRESULT hr;
251
252     shader->ID3D10VertexShader_iface.lpVtbl = &d3d10_vertex_shader_vtbl;
253     shader->refcount = 1;
254
255     shader_info.output_signature = &shader->output_signature;
256     hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info);
257     if (FAILED(hr))
258     {
259         ERR("Failed to extract shader, hr %#x.\n", hr);
260         return hr;
261     }
262
263     hr = wined3d_shader_create_vs(device->wined3d_device, shader_info.shader_code,
264             &shader->output_signature, shader, &d3d10_vertex_shader_wined3d_parent_ops, &shader->wined3d_shader, 4);
265     if (FAILED(hr))
266     {
267         WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
268         shader_free_signature(&shader->output_signature);
269         hr = E_INVALIDARG;
270         return hr;
271     }
272
273     return S_OK;
274 }
275
276 struct d3d10_vertex_shader *unsafe_impl_from_ID3D10VertexShader(ID3D10VertexShader *iface)
277 {
278     if (!iface)
279         return NULL;
280     assert(iface->lpVtbl == &d3d10_vertex_shader_vtbl);
281
282     return impl_from_ID3D10VertexShader(iface);
283 }
284
285 static inline struct d3d10_geometry_shader *impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
286 {
287     return CONTAINING_RECORD(iface, struct d3d10_geometry_shader, ID3D10GeometryShader_iface);
288 }
289
290 /* IUnknown methods */
291
292 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_QueryInterface(ID3D10GeometryShader *iface,
293         REFIID riid, void **object)
294 {
295     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
296
297     if (IsEqualGUID(riid, &IID_ID3D10GeometryShader)
298             || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
299             || IsEqualGUID(riid, &IID_IUnknown))
300     {
301         IUnknown_AddRef(iface);
302         *object = iface;
303         return S_OK;
304     }
305
306     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
307
308     *object = NULL;
309     return E_NOINTERFACE;
310 }
311
312 static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_AddRef(ID3D10GeometryShader *iface)
313 {
314     struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
315     ULONG refcount = InterlockedIncrement(&This->refcount);
316
317     TRACE("%p increasing refcount to %u\n", This, refcount);
318
319     return refcount;
320 }
321
322 static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_Release(ID3D10GeometryShader *iface)
323 {
324     struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
325     ULONG refcount = InterlockedDecrement(&This->refcount);
326
327     TRACE("%p decreasing refcount to %u\n", This, refcount);
328
329     if (!refcount)
330         wined3d_shader_decref(This->wined3d_shader);
331
332     return refcount;
333 }
334
335 /* ID3D10DeviceChild methods */
336
337 static void STDMETHODCALLTYPE d3d10_geometry_shader_GetDevice(ID3D10GeometryShader *iface, ID3D10Device **device)
338 {
339     FIXME("iface %p, device %p stub!\n", iface, device);
340 }
341
342 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_GetPrivateData(ID3D10GeometryShader *iface,
343         REFGUID guid, UINT *data_size, void *data)
344 {
345     FIXME("iface %p, guid %s, data_size %p, data %p stub!\n",
346             iface, debugstr_guid(guid), data_size, data);
347
348     return E_NOTIMPL;
349 }
350
351 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateData(ID3D10GeometryShader *iface,
352         REFGUID guid, UINT data_size, const void *data)
353 {
354     FIXME("iface %p, guid %s, data_size %u, data %p stub!\n",
355             iface, debugstr_guid(guid), data_size, data);
356
357     return E_NOTIMPL;
358 }
359
360 static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateDataInterface(ID3D10GeometryShader *iface,
361         REFGUID guid, const IUnknown *data)
362 {
363     FIXME("iface %p, guid %s, data %p stub!\n", iface, debugstr_guid(guid), data);
364
365     return E_NOTIMPL;
366 }
367
368 static const struct ID3D10GeometryShaderVtbl d3d10_geometry_shader_vtbl =
369 {
370     /* IUnknown methods */
371     d3d10_geometry_shader_QueryInterface,
372     d3d10_geometry_shader_AddRef,
373     d3d10_geometry_shader_Release,
374     /* ID3D10DeviceChild methods */
375     d3d10_geometry_shader_GetDevice,
376     d3d10_geometry_shader_GetPrivateData,
377     d3d10_geometry_shader_SetPrivateData,
378     d3d10_geometry_shader_SetPrivateDataInterface,
379 };
380
381 static void STDMETHODCALLTYPE d3d10_geometry_shader_wined3d_object_destroyed(void *parent)
382 {
383     struct d3d10_geometry_shader *shader = parent;
384     shader_free_signature(&shader->output_signature);
385     HeapFree(GetProcessHeap(), 0, shader);
386 }
387
388 static const struct wined3d_parent_ops d3d10_geometry_shader_wined3d_parent_ops =
389 {
390     d3d10_geometry_shader_wined3d_object_destroyed,
391 };
392
393 HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct d3d10_device *device,
394         const void *byte_code, SIZE_T byte_code_length)
395 {
396     struct d3d10_shader_info shader_info;
397     HRESULT hr;
398
399     shader->ID3D10GeometryShader_iface.lpVtbl = &d3d10_geometry_shader_vtbl;
400     shader->refcount = 1;
401
402     shader_info.output_signature = &shader->output_signature;
403     hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info);
404     if (FAILED(hr))
405     {
406         ERR("Failed to extract shader, hr %#x.\n", hr);
407         return hr;
408     }
409
410     hr = wined3d_shader_create_gs(device->wined3d_device, shader_info.shader_code,
411             &shader->output_signature, shader, &d3d10_geometry_shader_wined3d_parent_ops, &shader->wined3d_shader, 4);
412     if (FAILED(hr))
413     {
414         WARN("Failed to create wined3d geometry shader, hr %#x.\n", hr);
415         shader_free_signature(&shader->output_signature);
416         hr = E_INVALIDARG;
417         return hr;
418     }
419
420     return S_OK;
421 }
422
423 struct d3d10_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
424 {
425     if (!iface)
426         return NULL;
427     assert(iface->lpVtbl == &d3d10_geometry_shader_vtbl);
428
429     return impl_from_ID3D10GeometryShader(iface);
430 }
431
432 static inline struct d3d10_pixel_shader *impl_from_ID3D10PixelShader(ID3D10PixelShader *iface)
433 {
434     return CONTAINING_RECORD(iface, struct d3d10_pixel_shader, ID3D10PixelShader_iface);
435 }
436
437 /* IUnknown methods */
438
439 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_QueryInterface(ID3D10PixelShader *iface,
440         REFIID riid, void **object)
441 {
442     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
443
444     if (IsEqualGUID(riid, &IID_ID3D10PixelShader)
445             || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
446             || IsEqualGUID(riid, &IID_IUnknown))
447     {
448         IUnknown_AddRef(iface);
449         *object = iface;
450         return S_OK;
451     }
452
453     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
454
455     *object = NULL;
456     return E_NOINTERFACE;
457 }
458
459 static ULONG STDMETHODCALLTYPE d3d10_pixel_shader_AddRef(ID3D10PixelShader *iface)
460 {
461     struct d3d10_pixel_shader *This = impl_from_ID3D10PixelShader(iface);
462     ULONG refcount = InterlockedIncrement(&This->refcount);
463
464     TRACE("%p increasing refcount to %u\n", This, refcount);
465
466     if (refcount == 1)
467         wined3d_shader_incref(This->wined3d_shader);
468
469     return refcount;
470 }
471
472 static ULONG STDMETHODCALLTYPE d3d10_pixel_shader_Release(ID3D10PixelShader *iface)
473 {
474     struct d3d10_pixel_shader *This = impl_from_ID3D10PixelShader(iface);
475     ULONG refcount = InterlockedDecrement(&This->refcount);
476
477     TRACE("%p decreasing refcount to %u\n", This, refcount);
478
479     if (!refcount)
480         wined3d_shader_decref(This->wined3d_shader);
481
482     return refcount;
483 }
484
485 /* ID3D10DeviceChild methods */
486
487 static void STDMETHODCALLTYPE d3d10_pixel_shader_GetDevice(ID3D10PixelShader *iface, ID3D10Device **device)
488 {
489     FIXME("iface %p, device %p stub!\n", iface, device);
490 }
491
492 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_GetPrivateData(ID3D10PixelShader *iface,
493         REFGUID guid, UINT *data_size, void *data)
494 {
495     FIXME("iface %p, guid %s, data_size %p, data %p stub!\n",
496             iface, debugstr_guid(guid), data_size, data);
497
498     return E_NOTIMPL;
499 }
500
501 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_SetPrivateData(ID3D10PixelShader *iface,
502         REFGUID guid, UINT data_size, const void *data)
503 {
504     FIXME("iface %p, guid %s, data_size %u, data %p stub!\n",
505             iface, debugstr_guid(guid), data_size, data);
506
507     return E_NOTIMPL;
508 }
509
510 static HRESULT STDMETHODCALLTYPE d3d10_pixel_shader_SetPrivateDataInterface(ID3D10PixelShader *iface,
511         REFGUID guid, const IUnknown *data)
512 {
513     FIXME("iface %p, guid %s, data %p stub!\n", iface, debugstr_guid(guid), data);
514
515     return E_NOTIMPL;
516 }
517
518 static const struct ID3D10PixelShaderVtbl d3d10_pixel_shader_vtbl =
519 {
520     /* IUnknown methods */
521     d3d10_pixel_shader_QueryInterface,
522     d3d10_pixel_shader_AddRef,
523     d3d10_pixel_shader_Release,
524     /* ID3D10DeviceChild methods */
525     d3d10_pixel_shader_GetDevice,
526     d3d10_pixel_shader_GetPrivateData,
527     d3d10_pixel_shader_SetPrivateData,
528     d3d10_pixel_shader_SetPrivateDataInterface,
529 };
530
531 static void STDMETHODCALLTYPE d3d10_pixel_shader_wined3d_object_destroyed(void *parent)
532 {
533     struct d3d10_pixel_shader *shader = parent;
534     shader_free_signature(&shader->output_signature);
535     HeapFree(GetProcessHeap(), 0, shader);
536 }
537
538 static const struct wined3d_parent_ops d3d10_pixel_shader_wined3d_parent_ops =
539 {
540     d3d10_pixel_shader_wined3d_object_destroyed,
541 };
542
543 HRESULT d3d10_pixel_shader_init(struct d3d10_pixel_shader *shader, struct d3d10_device *device,
544         const void *byte_code, SIZE_T byte_code_length)
545 {
546     struct d3d10_shader_info shader_info;
547     HRESULT hr;
548
549     shader->ID3D10PixelShader_iface.lpVtbl = &d3d10_pixel_shader_vtbl;
550     shader->refcount = 1;
551
552     shader_info.output_signature = &shader->output_signature;
553     hr = shader_extract_from_dxbc(byte_code, byte_code_length, &shader_info);
554     if (FAILED(hr))
555     {
556         ERR("Failed to extract shader, hr %#x.\n", hr);
557         return hr;
558     }
559
560     hr = wined3d_shader_create_ps(device->wined3d_device, shader_info.shader_code,
561             &shader->output_signature, shader, &d3d10_pixel_shader_wined3d_parent_ops, &shader->wined3d_shader, 4);
562     if (FAILED(hr))
563     {
564         WARN("Failed to create wined3d pixel shader, hr %#x.\n", hr);
565         shader_free_signature(&shader->output_signature);
566         hr = E_INVALIDARG;
567         return hr;
568     }
569
570     return S_OK;
571 }
572
573 struct d3d10_pixel_shader *unsafe_impl_from_ID3D10PixelShader(ID3D10PixelShader *iface)
574 {
575     if (!iface)
576         return NULL;
577     assert(iface->lpVtbl == &d3d10_pixel_shader_vtbl);
578
579     return impl_from_ID3D10PixelShader(iface);
580 }