xref: /reactos/dll/directx/wine/d3dcompiler_43/blob.c (revision 3c774903)
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 }
466 
467 HRESULT WINAPI D3DReadFileToBlob(const WCHAR *filename, ID3DBlob **contents)
468 {
469     FIXME("filename %s, contents %p\n", debugstr_w(filename), contents);
470 
471     return E_NOTIMPL;
472 }
473 
474 HRESULT WINAPI D3DWriteBlobToFile(ID3DBlob* blob, const WCHAR *filename, BOOL overwrite)
475 {
476     FIXME("blob %p, filename %s, overwrite %d\n", blob, debugstr_w(filename), overwrite);
477 
478     return E_NOTIMPL;
479 }
480