Release 1.5.29.
[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         return E_OUTOFMEMORY;
152
153     hr = d3dcompiler_blob_init(object, data_size);
154     if (FAILED(hr))
155     {
156         WARN("Failed to initialize blob, hr %#x.\n", hr);
157         HeapFree(GetProcessHeap(), 0, object);
158         return hr;
159     }
160
161     *blob = &object->ID3DBlob_iface;
162
163     TRACE("Created ID3DBlob %p\n", *blob);
164
165     return S_OK;
166 }
167
168 static BOOL check_blob_part(DWORD tag, D3D_BLOB_PART part)
169 {
170     BOOL add = FALSE;
171
172     switch(part)
173     {
174         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
175             if (tag == TAG_ISGN) add = TRUE;
176             break;
177
178         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
179             if (tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
180             break;
181
182         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
183             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
184             break;
185
186         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
187             if (tag == TAG_PCSG) add = TRUE;
188             break;
189
190         case D3D_BLOB_ALL_SIGNATURE_BLOB:
191             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5 || tag == TAG_PCSG) add = TRUE;
192             break;
193
194         case D3D_BLOB_DEBUG_INFO:
195             if (tag == TAG_SDBG) add = TRUE;
196             break;
197
198         case D3D_BLOB_LEGACY_SHADER:
199             if (tag == TAG_Aon9) add = TRUE;
200             break;
201
202         case D3D_BLOB_XNA_PREPASS_SHADER:
203             if (tag == TAG_XNAP) add = TRUE;
204             break;
205
206         case D3D_BLOB_XNA_SHADER:
207             if (tag == TAG_XNAS) add = TRUE;
208             break;
209
210         default:
211             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
212             break;
213     }
214
215     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
216
217     return add;
218 }
219
220 static HRESULT d3dcompiler_get_blob_part(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
221 {
222     struct dxbc src_dxbc, dst_dxbc;
223     HRESULT hr;
224     unsigned int i, count;
225
226     if (!data || !data_size || flags || !blob)
227     {
228         WARN("Invalid arguments: data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
229         return D3DERR_INVALIDCALL;
230     }
231
232     if (part > D3D_BLOB_TEST_COMPILE_PERF
233             || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
234     {
235         WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
236         return D3DERR_INVALIDCALL;
237     }
238
239     hr = dxbc_parse(data, data_size, &src_dxbc);
240     if (FAILED(hr))
241     {
242         WARN("Failed to parse blob part\n");
243         return hr;
244     }
245
246     hr = dxbc_init(&dst_dxbc, 0);
247     if (FAILED(hr))
248     {
249         dxbc_destroy(&src_dxbc);
250         WARN("Failed to init dxbc\n");
251         return hr;
252     }
253
254     for (i = 0; i < src_dxbc.count; ++i)
255     {
256         struct dxbc_section *section = &src_dxbc.sections[i];
257
258         if (check_blob_part(section->tag, part))
259         {
260             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
261             if (FAILED(hr))
262             {
263                 dxbc_destroy(&src_dxbc);
264                 dxbc_destroy(&dst_dxbc);
265                 WARN("Failed to add section to dxbc\n");
266                 return hr;
267             }
268         }
269     }
270
271     count = dst_dxbc.count;
272
273     switch(part)
274     {
275         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
276         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
277         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
278         case D3D_BLOB_DEBUG_INFO:
279         case D3D_BLOB_LEGACY_SHADER:
280         case D3D_BLOB_XNA_PREPASS_SHADER:
281         case D3D_BLOB_XNA_SHADER:
282             if (count != 1) count = 0;
283             break;
284
285         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
286             if (count != 2) count = 0;
287             break;
288
289         case D3D_BLOB_ALL_SIGNATURE_BLOB:
290             if (count != 3) count = 0;
291             break;
292
293         default:
294             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
295             break;
296     }
297
298     if (count == 0)
299     {
300         dxbc_destroy(&src_dxbc);
301         dxbc_destroy(&dst_dxbc);
302         WARN("Nothing to write into the blob (count = 0)\n");
303         return E_FAIL;
304     }
305
306     /* some parts aren't full DXBCs, they contain only the data */
307     if (count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER || part == D3D_BLOB_XNA_PREPASS_SHADER
308             || part == D3D_BLOB_XNA_SHADER))
309     {
310         hr = D3DCreateBlob(dst_dxbc.sections[0].data_size, blob);
311         if (SUCCEEDED(hr))
312         {
313             memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.sections[0].data, dst_dxbc.sections[0].data_size);
314         }
315         else
316         {
317             WARN("Could not create blob\n");
318         }
319     }
320     else
321     {
322         hr = dxbc_write_blob(&dst_dxbc, blob);
323         if (FAILED(hr))
324         {
325             WARN("Failed to write blob part\n");
326         }
327     }
328
329     dxbc_destroy(&src_dxbc);
330     dxbc_destroy(&dst_dxbc);
331
332     return hr;
333 }
334
335 static BOOL check_blob_strip(DWORD tag, UINT flags)
336 {
337     BOOL add = TRUE;
338
339     if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
340
341     switch(tag)
342     {
343         case TAG_RDEF:
344         case TAG_STAT:
345             if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
346             break;
347
348         case TAG_SDBG:
349             if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
350             break;
351
352         default:
353             break;
354     }
355
356     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
357
358     return add;
359 }
360
361 static HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
362 {
363     struct dxbc src_dxbc, dst_dxbc;
364     HRESULT hr;
365     unsigned int i;
366
367     if (!blob)
368     {
369         WARN("NULL for blob specified\n");
370         return E_FAIL;
371     }
372
373     if (!data || !data_size)
374     {
375         WARN("Invalid arguments: data %p, data_size %lu\n", data, data_size);
376         return D3DERR_INVALIDCALL;
377     }
378
379     hr = dxbc_parse(data, data_size, &src_dxbc);
380     if (FAILED(hr))
381     {
382         WARN("Failed to parse blob part\n");
383         return hr;
384     }
385
386     /* src_dxbc.count >= dst_dxbc.count */
387     hr = dxbc_init(&dst_dxbc, src_dxbc.count);
388     if (FAILED(hr))
389     {
390         dxbc_destroy(&src_dxbc);
391         WARN("Failed to init dxbc\n");
392         return hr;
393     }
394
395     for (i = 0; i < src_dxbc.count; ++i)
396     {
397         struct dxbc_section *section = &src_dxbc.sections[i];
398
399         if (check_blob_strip(section->tag, flags))
400         {
401             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
402             if (FAILED(hr))
403             {
404                 dxbc_destroy(&src_dxbc);
405                 dxbc_destroy(&dst_dxbc);
406                 WARN("Failed to add section to dxbc\n");
407                 return hr;
408             }
409         }
410     }
411
412     hr = dxbc_write_blob(&dst_dxbc, blob);
413     if (FAILED(hr))
414     {
415         WARN("Failed to write blob part\n");
416     }
417
418     dxbc_destroy(&src_dxbc);
419     dxbc_destroy(&dst_dxbc);
420
421     return hr;
422 }
423
424 HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
425 {
426     TRACE("data %p, data_size %lu, part %s, flags %#x, blob %p\n", data,
427            data_size, debug_d3dcompiler_d3d_blob_part(part), flags, blob);
428
429     return d3dcompiler_get_blob_part(data, data_size, part, flags, blob);
430 }
431
432 HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
433 {
434     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
435
436     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob);
437 }
438
439 HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
440 {
441     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
442
443     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob);
444 }
445
446 HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
447 {
448     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
449
450     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob);
451 }
452
453 HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob)
454 {
455     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
456
457     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob);
458 }
459
460 HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3D10Blob **blob)
461 {
462     TRACE("data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
463
464     return d3dcompiler_strip_shader(data, data_size, flags, blob);
465 }