shdocvw: Use task destructors for releasing task params.
[wine] / dlls / d3dcompiler_43 / blob.c
1 /*
2  * Direct3D blob file
3  *
4  * Copyright 2010 Rico Schüller
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include "d3dcompiler_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler);
28
29 struct d3dcompiler_blob
30 {
31     ID3DBlob ID3DBlob_iface;
32     LONG refcount;
33
34     SIZE_T size;
35     void *data;
36 };
37
38 static inline struct d3dcompiler_blob *impl_from_ID3DBlob(ID3DBlob *iface)
39 {
40     return CONTAINING_RECORD(iface, struct d3dcompiler_blob, ID3DBlob_iface);
41 }
42
43 /* IUnknown methods */
44
45 static HRESULT STDMETHODCALLTYPE d3dcompiler_blob_QueryInterface(ID3DBlob *iface, REFIID riid, void **object)
46 {
47     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
48
49     if (IsEqualGUID(riid, &IID_ID3D10Blob)
50             || IsEqualGUID(riid, &IID_IUnknown))
51     {
52         IUnknown_AddRef(iface);
53         *object = iface;
54         return S_OK;
55     }
56
57     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
58
59     *object = NULL;
60     return E_NOINTERFACE;
61 }
62
63 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_AddRef(ID3DBlob *iface)
64 {
65     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
66     ULONG refcount = InterlockedIncrement(&blob->refcount);
67
68     TRACE("%p increasing refcount to %u\n", blob, refcount);
69
70     return refcount;
71 }
72
73 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_Release(ID3DBlob *iface)
74 {
75     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
76     ULONG refcount = InterlockedDecrement(&blob->refcount);
77
78     TRACE("%p decreasing refcount to %u\n", blob, refcount);
79
80     if (!refcount)
81     {
82         HeapFree(GetProcessHeap(), 0, blob->data);
83         HeapFree(GetProcessHeap(), 0, blob);
84     }
85
86     return refcount;
87 }
88
89 /* ID3DBlob methods */
90
91 static void * STDMETHODCALLTYPE d3dcompiler_blob_GetBufferPointer(ID3DBlob *iface)
92 {
93     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
94
95     TRACE("iface %p\n", iface);
96
97     return blob->data;
98 }
99
100 static SIZE_T STDMETHODCALLTYPE d3dcompiler_blob_GetBufferSize(ID3DBlob *iface)
101 {
102     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
103
104     TRACE("iface %p\n", iface);
105
106     return blob->size;
107 }
108
109 static const struct ID3D10BlobVtbl d3dcompiler_blob_vtbl =
110 {
111     /* IUnknown methods */
112     d3dcompiler_blob_QueryInterface,
113     d3dcompiler_blob_AddRef,
114     d3dcompiler_blob_Release,
115     /* ID3DBlob methods */
116     d3dcompiler_blob_GetBufferPointer,
117     d3dcompiler_blob_GetBufferSize,
118 };
119
120 static HRESULT d3dcompiler_blob_init(struct d3dcompiler_blob *blob, SIZE_T data_size)
121 {
122     blob->ID3DBlob_iface.lpVtbl = &d3dcompiler_blob_vtbl;
123     blob->refcount = 1;
124     blob->size = data_size;
125
126     blob->data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
127     if (!blob->data)
128     {
129         ERR("Failed to allocate D3D blob data memory\n");
130         return E_OUTOFMEMORY;
131     }
132
133     return S_OK;
134 }
135
136 HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob)
137 {
138     struct d3dcompiler_blob *object;
139     HRESULT hr;
140
141     TRACE("data_size %lu, blob %p\n", data_size, blob);
142
143     if (!blob)
144     {
145         WARN("Invalid blob specified.\n");
146         return D3DERR_INVALIDCALL;
147     }
148
149     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
150     if (!object)
151     {
152         ERR("Failed to allocate D3D blob object memory\n");
153         return E_OUTOFMEMORY;
154     }
155
156     hr = d3dcompiler_blob_init(object, data_size);
157     if (FAILED(hr))
158     {
159         WARN("Failed to initialize blob, hr %#x.\n", hr);
160         HeapFree(GetProcessHeap(), 0, object);
161         return hr;
162     }
163
164     *blob = &object->ID3DBlob_iface;
165
166     TRACE("Created ID3DBlob %p\n", *blob);
167
168     return S_OK;
169 }
170
171 static BOOL check_blob_part(DWORD tag, D3D_BLOB_PART part)
172 {
173     BOOL add = FALSE;
174
175     switch(part)
176     {
177         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
178             if (tag == TAG_ISGN) add = TRUE;
179             break;
180
181         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
182             if (tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
183             break;
184
185         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
186             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
187             break;
188
189         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
190             if (tag == TAG_PCSG) add = TRUE;
191             break;
192
193         case D3D_BLOB_ALL_SIGNATURE_BLOB:
194             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5 || tag == TAG_PCSG) add = TRUE;
195             break;
196
197         case D3D_BLOB_DEBUG_INFO:
198             if (tag == TAG_SDBG) add = TRUE;
199             break;
200
201         case D3D_BLOB_LEGACY_SHADER:
202             if (tag == TAG_Aon9) add = TRUE;
203             break;
204
205         case D3D_BLOB_XNA_PREPASS_SHADER:
206             if (tag == TAG_XNAP) add = TRUE;
207             break;
208
209         case D3D_BLOB_XNA_SHADER:
210             if (tag == TAG_XNAS) add = TRUE;
211             break;
212
213         default:
214             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
215             break;
216     }
217
218     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
219
220     return add;
221 }
222
223 static HRESULT d3dcompiler_get_blob_part(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
224 {
225     struct dxbc src_dxbc, dst_dxbc;
226     HRESULT hr;
227     unsigned int i, count;
228
229     if (!data || !data_size || flags || !blob)
230     {
231         WARN("Invalid arguments: data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
232         return D3DERR_INVALIDCALL;
233     }
234
235     if (part > D3D_BLOB_TEST_COMPILE_PERF
236             || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
237     {
238         WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
239         return D3DERR_INVALIDCALL;
240     }
241
242     hr = dxbc_parse(data, data_size, &src_dxbc);
243     if (FAILED(hr))
244     {
245         WARN("Failed to parse blob part\n");
246         return hr;
247     }
248
249     hr = dxbc_init(&dst_dxbc, 0);
250     if (FAILED(hr))
251     {
252         dxbc_destroy(&src_dxbc);
253         WARN("Failed to init dxbc\n");
254         return hr;
255     }
256
257     for (i = 0; i < src_dxbc.count; ++i)
258     {
259         struct dxbc_section *section = &src_dxbc.sections[i];
260
261         if (check_blob_part(section->tag, part))
262         {
263             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
264             if (FAILED(hr))
265             {
266                 dxbc_destroy(&src_dxbc);
267                 dxbc_destroy(&dst_dxbc);
268                 WARN("Failed to add section to dxbc\n");
269                 return hr;
270             }
271         }
272     }
273
274     count = dst_dxbc.count;
275
276     switch(part)
277     {
278         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
279         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
280         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
281         case D3D_BLOB_DEBUG_INFO:
282         case D3D_BLOB_LEGACY_SHADER:
283         case D3D_BLOB_XNA_PREPASS_SHADER:
284         case D3D_BLOB_XNA_SHADER:
285             if (count != 1) count = 0;
286             break;
287
288         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
289             if (count != 2) count = 0;
290             break;
291
292         case D3D_BLOB_ALL_SIGNATURE_BLOB:
293             if (count != 3) count = 0;
294             break;
295
296         default:
297             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
298             break;
299     }
300
301     if (count == 0)
302     {
303         dxbc_destroy(&src_dxbc);
304         dxbc_destroy(&dst_dxbc);
305         WARN("Nothing to write into the blob (count = 0)\n");
306         return E_FAIL;
307     }
308
309     /* some parts aren't full DXBCs, they contain only the data */
310     if (count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER || part == D3D_BLOB_XNA_PREPASS_SHADER
311             || part == D3D_BLOB_XNA_SHADER))
312     {
313         hr = D3DCreateBlob(dst_dxbc.sections[0].data_size, blob);
314         if (SUCCEEDED(hr))
315         {
316             memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.sections[0].data, dst_dxbc.sections[0].data_size);
317         }
318         else
319         {
320             WARN("Could not create blob\n");
321         }
322     }
323     else
324     {
325         hr = dxbc_write_blob(&dst_dxbc, blob);
326         if (FAILED(hr))
327         {
328             WARN("Failed to write blob part\n");
329         }
330     }
331
332     dxbc_destroy(&src_dxbc);
333     dxbc_destroy(&dst_dxbc);
334
335     return hr;
336 }
337
338 static BOOL check_blob_strip(DWORD tag, UINT flags)
339 {
340     BOOL add = TRUE;
341
342     if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
343
344     switch(tag)
345     {
346         case TAG_RDEF:
347         case TAG_STAT:
348             if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
349             break;
350
351         case TAG_SDBG:
352             if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
353             break;
354
355         default:
356             break;
357     }
358
359     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
360
361     return add;
362 }
363
364 static HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
365 {
366     struct dxbc src_dxbc, dst_dxbc;
367     HRESULT hr;
368     unsigned int i;
369
370     if (!blob)
371     {
372         WARN("NULL for blob specified\n");
373         return E_FAIL;
374     }
375
376     if (!data || !data_size)
377     {
378         WARN("Invalid arguments: data %p, data_size %lu\n", data, data_size);
379         return D3DERR_INVALIDCALL;
380     }
381
382     hr = dxbc_parse(data, data_size, &src_dxbc);
383     if (FAILED(hr))
384     {
385         WARN("Failed to parse blob part\n");
386         return hr;
387     }
388
389     /* src_dxbc.count >= dst_dxbc.count */
390     hr = dxbc_init(&dst_dxbc, src_dxbc.count);
391     if (FAILED(hr))
392     {
393         dxbc_destroy(&src_dxbc);
394         WARN("Failed to init dxbc\n");
395         return hr;
396     }
397
398     for (i = 0; i < src_dxbc.count; ++i)
399     {
400         struct dxbc_section *section = &src_dxbc.sections[i];
401
402         if (check_blob_strip(section->tag, flags))
403         {
404             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
405             if (FAILED(hr))
406             {
407                 dxbc_destroy(&src_dxbc);
408                 dxbc_destroy(&dst_dxbc);
409                 WARN("Failed to add section to dxbc\n");
410                 return hr;
411             }
412         }
413     }
414
415     hr = dxbc_write_blob(&dst_dxbc, blob);
416     if (FAILED(hr))
417     {
418         WARN("Failed to write blob part\n");
419     }
420
421     dxbc_destroy(&src_dxbc);
422     dxbc_destroy(&dst_dxbc);
423
424     return hr;
425 }
426
427 HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
428 {
429     TRACE("data %p, data_size %lu, part %s, flags %#x, blob %p\n", data,
430            data_size, debug_d3dcompiler_d3d_blob_part(part), flags, blob);
431
432     return d3dcompiler_get_blob_part(data, data_size, part, flags, blob);
433 }
434
435 HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
436 {
437     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
438
439     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob);
440 }
441
442 HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
443 {
444     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
445
446     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob);
447 }
448
449 HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
450 {
451     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
452
453     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob);
454 }
455
456 HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob)
457 {
458     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
459
460     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob);
461 }
462
463 HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3D10Blob **blob)
464 {
465     TRACE("data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
466
467     return d3dcompiler_strip_shader(data, data_size, flags, blob);
468 }