xref: /reactos/dll/directx/wine/d3dcompiler_43/blob.c (revision dffb99c1)
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 "d3dcompiler_private.h"
23 
24 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler);
25 
26 struct d3dcompiler_blob
27 {
28     ID3DBlob ID3DBlob_iface;
29     LONG refcount;
30 
31     SIZE_T size;
32     void *data;
33 };
34 
impl_from_ID3DBlob(ID3DBlob * iface)35 static inline struct d3dcompiler_blob *impl_from_ID3DBlob(ID3DBlob *iface)
36 {
37     return CONTAINING_RECORD(iface, struct d3dcompiler_blob, ID3DBlob_iface);
38 }
39 
40 /* IUnknown methods */
41 
d3dcompiler_blob_QueryInterface(ID3DBlob * iface,REFIID riid,void ** object)42 static HRESULT STDMETHODCALLTYPE d3dcompiler_blob_QueryInterface(ID3DBlob *iface, REFIID riid, void **object)
43 {
44     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
45 
46     if (IsEqualGUID(riid, &IID_ID3D10Blob)
47             || IsEqualGUID(riid, &IID_IUnknown))
48     {
49         IUnknown_AddRef(iface);
50         *object = iface;
51         return S_OK;
52     }
53 
54     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
55 
56     *object = NULL;
57     return E_NOINTERFACE;
58 }
59 
d3dcompiler_blob_AddRef(ID3DBlob * iface)60 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_AddRef(ID3DBlob *iface)
61 {
62     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
63     ULONG refcount = InterlockedIncrement(&blob->refcount);
64 
65     TRACE("%p increasing refcount to %u\n", blob, refcount);
66 
67     return refcount;
68 }
69 
d3dcompiler_blob_Release(ID3DBlob * iface)70 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_Release(ID3DBlob *iface)
71 {
72     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
73     ULONG refcount = InterlockedDecrement(&blob->refcount);
74 
75     TRACE("%p decreasing refcount to %u\n", blob, refcount);
76 
77     if (!refcount)
78     {
79         HeapFree(GetProcessHeap(), 0, blob->data);
80         HeapFree(GetProcessHeap(), 0, blob);
81     }
82 
83     return refcount;
84 }
85 
86 /* ID3DBlob methods */
87 
d3dcompiler_blob_GetBufferPointer(ID3DBlob * iface)88 static void * STDMETHODCALLTYPE d3dcompiler_blob_GetBufferPointer(ID3DBlob *iface)
89 {
90     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
91 
92     TRACE("iface %p\n", iface);
93 
94     return blob->data;
95 }
96 
d3dcompiler_blob_GetBufferSize(ID3DBlob * iface)97 static SIZE_T STDMETHODCALLTYPE d3dcompiler_blob_GetBufferSize(ID3DBlob *iface)
98 {
99     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
100 
101     TRACE("iface %p\n", iface);
102 
103     return blob->size;
104 }
105 
106 static const struct ID3D10BlobVtbl d3dcompiler_blob_vtbl =
107 {
108     /* IUnknown methods */
109     d3dcompiler_blob_QueryInterface,
110     d3dcompiler_blob_AddRef,
111     d3dcompiler_blob_Release,
112     /* ID3DBlob methods */
113     d3dcompiler_blob_GetBufferPointer,
114     d3dcompiler_blob_GetBufferSize,
115 };
116 
d3dcompiler_blob_init(struct d3dcompiler_blob * blob,SIZE_T data_size)117 static HRESULT d3dcompiler_blob_init(struct d3dcompiler_blob *blob, SIZE_T data_size)
118 {
119     blob->ID3DBlob_iface.lpVtbl = &d3dcompiler_blob_vtbl;
120     blob->refcount = 1;
121     blob->size = data_size;
122 
123     blob->data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
124     if (!blob->data)
125     {
126         ERR("Failed to allocate D3D blob data memory\n");
127         return E_OUTOFMEMORY;
128     }
129 
130     return S_OK;
131 }
132 
D3DCreateBlob(SIZE_T data_size,ID3DBlob ** blob)133 HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob)
134 {
135     struct d3dcompiler_blob *object;
136     HRESULT hr;
137 
138     TRACE("data_size %lu, blob %p\n", data_size, blob);
139 
140     if (!blob)
141     {
142         WARN("Invalid blob specified.\n");
143         return D3DERR_INVALIDCALL;
144     }
145 
146     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
147     if (!object)
148         return E_OUTOFMEMORY;
149 
150     hr = d3dcompiler_blob_init(object, data_size);
151     if (FAILED(hr))
152     {
153         WARN("Failed to initialize blob, hr %#x.\n", hr);
154         HeapFree(GetProcessHeap(), 0, object);
155         return hr;
156     }
157 
158     *blob = &object->ID3DBlob_iface;
159 
160     TRACE("Created ID3DBlob %p\n", *blob);
161 
162     return S_OK;
163 }
164 
check_blob_part(DWORD tag,D3D_BLOB_PART part)165 static BOOL check_blob_part(DWORD tag, D3D_BLOB_PART part)
166 {
167     BOOL add = FALSE;
168 
169     switch(part)
170     {
171         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
172             if (tag == TAG_ISGN) add = TRUE;
173             break;
174 
175         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
176             if (tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
177             break;
178 
179         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
180             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
181             break;
182 
183         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
184             if (tag == TAG_PCSG) add = TRUE;
185             break;
186 
187         case D3D_BLOB_ALL_SIGNATURE_BLOB:
188             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5 || tag == TAG_PCSG) add = TRUE;
189             break;
190 
191         case D3D_BLOB_DEBUG_INFO:
192             if (tag == TAG_SDBG) add = TRUE;
193             break;
194 
195         case D3D_BLOB_LEGACY_SHADER:
196             if (tag == TAG_Aon9) add = TRUE;
197             break;
198 
199         case D3D_BLOB_XNA_PREPASS_SHADER:
200             if (tag == TAG_XNAP) add = TRUE;
201             break;
202 
203         case D3D_BLOB_XNA_SHADER:
204             if (tag == TAG_XNAS) add = TRUE;
205             break;
206 
207         default:
208             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
209             break;
210     }
211 
212     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
213 
214     return add;
215 }
216 
d3dcompiler_get_blob_part(const void * data,SIZE_T data_size,D3D_BLOB_PART part,UINT flags,ID3DBlob ** blob)217 static HRESULT d3dcompiler_get_blob_part(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
218 {
219     struct dxbc src_dxbc, dst_dxbc;
220     HRESULT hr;
221     unsigned int i, count;
222 
223     if (!data || !data_size || flags || !blob)
224     {
225         WARN("Invalid arguments: data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
226         return D3DERR_INVALIDCALL;
227     }
228 
229     if (part > D3D_BLOB_TEST_COMPILE_PERF
230             || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
231     {
232         WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
233         return D3DERR_INVALIDCALL;
234     }
235 
236     hr = dxbc_parse(data, data_size, &src_dxbc);
237     if (FAILED(hr))
238     {
239         WARN("Failed to parse blob part\n");
240         return hr;
241     }
242 
243     hr = dxbc_init(&dst_dxbc, 0);
244     if (FAILED(hr))
245     {
246         dxbc_destroy(&src_dxbc);
247         WARN("Failed to init dxbc\n");
248         return hr;
249     }
250 
251     for (i = 0; i < src_dxbc.count; ++i)
252     {
253         struct dxbc_section *section = &src_dxbc.sections[i];
254 
255         if (check_blob_part(section->tag, part))
256         {
257             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
258             if (FAILED(hr))
259             {
260                 dxbc_destroy(&src_dxbc);
261                 dxbc_destroy(&dst_dxbc);
262                 WARN("Failed to add section to dxbc\n");
263                 return hr;
264             }
265         }
266     }
267 
268     count = dst_dxbc.count;
269 
270     switch(part)
271     {
272         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
273         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
274         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
275         case D3D_BLOB_DEBUG_INFO:
276         case D3D_BLOB_LEGACY_SHADER:
277         case D3D_BLOB_XNA_PREPASS_SHADER:
278         case D3D_BLOB_XNA_SHADER:
279             if (count != 1) count = 0;
280             break;
281 
282         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
283             if (count != 2) count = 0;
284             break;
285 
286         case D3D_BLOB_ALL_SIGNATURE_BLOB:
287             if (count != 3) count = 0;
288             break;
289 
290         default:
291             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
292             break;
293     }
294 
295     if (count == 0)
296     {
297         dxbc_destroy(&src_dxbc);
298         dxbc_destroy(&dst_dxbc);
299         WARN("Nothing to write into the blob (count = 0)\n");
300         return E_FAIL;
301     }
302 
303     /* some parts aren't full DXBCs, they contain only the data */
304     if (count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER || part == D3D_BLOB_XNA_PREPASS_SHADER
305             || part == D3D_BLOB_XNA_SHADER))
306     {
307         hr = D3DCreateBlob(dst_dxbc.sections[0].data_size, blob);
308         if (SUCCEEDED(hr))
309         {
310             memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.sections[0].data, dst_dxbc.sections[0].data_size);
311         }
312         else
313         {
314             WARN("Could not create blob\n");
315         }
316     }
317     else
318     {
319         hr = dxbc_write_blob(&dst_dxbc, blob);
320         if (FAILED(hr))
321         {
322             WARN("Failed to write blob part\n");
323         }
324     }
325 
326     dxbc_destroy(&src_dxbc);
327     dxbc_destroy(&dst_dxbc);
328 
329     return hr;
330 }
331 
check_blob_strip(DWORD tag,UINT flags)332 static BOOL check_blob_strip(DWORD tag, UINT flags)
333 {
334     BOOL add = TRUE;
335 
336     if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
337 
338     switch(tag)
339     {
340         case TAG_RDEF:
341         case TAG_STAT:
342             if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
343             break;
344 
345         case TAG_SDBG:
346             if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
347             break;
348 
349         default:
350             break;
351     }
352 
353     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
354 
355     return add;
356 }
357 
d3dcompiler_strip_shader(const void * data,SIZE_T data_size,UINT flags,ID3DBlob ** blob)358 static HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
359 {
360     struct dxbc src_dxbc, dst_dxbc;
361     HRESULT hr;
362     unsigned int i;
363 
364     if (!blob)
365     {
366         WARN("NULL for blob specified\n");
367         return E_FAIL;
368     }
369 
370     if (!data || !data_size)
371     {
372         WARN("Invalid arguments: data %p, data_size %lu\n", data, data_size);
373         return D3DERR_INVALIDCALL;
374     }
375 
376     hr = dxbc_parse(data, data_size, &src_dxbc);
377     if (FAILED(hr))
378     {
379         WARN("Failed to parse blob part\n");
380         return hr;
381     }
382 
383     /* src_dxbc.count >= dst_dxbc.count */
384     hr = dxbc_init(&dst_dxbc, src_dxbc.count);
385     if (FAILED(hr))
386     {
387         dxbc_destroy(&src_dxbc);
388         WARN("Failed to init dxbc\n");
389         return hr;
390     }
391 
392     for (i = 0; i < src_dxbc.count; ++i)
393     {
394         struct dxbc_section *section = &src_dxbc.sections[i];
395 
396         if (check_blob_strip(section->tag, flags))
397         {
398             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
399             if (FAILED(hr))
400             {
401                 dxbc_destroy(&src_dxbc);
402                 dxbc_destroy(&dst_dxbc);
403                 WARN("Failed to add section to dxbc\n");
404                 return hr;
405             }
406         }
407     }
408 
409     hr = dxbc_write_blob(&dst_dxbc, blob);
410     if (FAILED(hr))
411     {
412         WARN("Failed to write blob part\n");
413     }
414 
415     dxbc_destroy(&src_dxbc);
416     dxbc_destroy(&dst_dxbc);
417 
418     return hr;
419 }
420 
D3DGetBlobPart(const void * data,SIZE_T data_size,D3D_BLOB_PART part,UINT flags,ID3DBlob ** blob)421 HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
422 {
423     TRACE("data %p, data_size %lu, part %s, flags %#x, blob %p\n", data,
424            data_size, debug_d3dcompiler_d3d_blob_part(part), flags, blob);
425 
426     return d3dcompiler_get_blob_part(data, data_size, part, flags, blob);
427 }
428 
D3DGetInputSignatureBlob(const void * data,SIZE_T data_size,ID3DBlob ** blob)429 HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
430 {
431     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
432 
433     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob);
434 }
435 
D3DGetOutputSignatureBlob(const void * data,SIZE_T data_size,ID3DBlob ** blob)436 HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
437 {
438     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
439 
440     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob);
441 }
442 
D3DGetInputAndOutputSignatureBlob(const void * data,SIZE_T data_size,ID3DBlob ** blob)443 HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
444 {
445     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
446 
447     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob);
448 }
449 
D3DGetDebugInfo(const void * data,SIZE_T data_size,ID3DBlob ** blob)450 HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob)
451 {
452     TRACE("data %p, data_size %lu, blob %p\n", data, data_size, blob);
453 
454     return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob);
455 }
456 
D3DStripShader(const void * data,SIZE_T data_size,UINT flags,ID3D10Blob ** blob)457 HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3D10Blob **blob)
458 {
459     TRACE("data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
460 
461     return d3dcompiler_strip_shader(data, data_size, flags, blob);
462 }
463 
D3DReadFileToBlob(const WCHAR * filename,ID3DBlob ** contents)464 HRESULT WINAPI D3DReadFileToBlob(const WCHAR *filename, ID3DBlob **contents)
465 {
466     struct d3dcompiler_blob *object;
467     SIZE_T data_size;
468     DWORD read_size;
469     HANDLE file;
470     HRESULT hr;
471 
472     TRACE("filename %s, contents %p.\n", debugstr_w(filename), contents);
473 
474     file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
475     if (file == INVALID_HANDLE_VALUE)
476         return HRESULT_FROM_WIN32(GetLastError());
477 
478     data_size = GetFileSize(file, NULL);
479     if (data_size == INVALID_FILE_SIZE)
480     {
481         CloseHandle(file);
482         return HRESULT_FROM_WIN32(GetLastError());
483     }
484 
485     if (!(object = heap_alloc_zero(sizeof(*object))))
486     {
487         CloseHandle(file);
488         return E_OUTOFMEMORY;
489     }
490 
491     if (FAILED(hr = d3dcompiler_blob_init(object, data_size)))
492     {
493         WARN("Failed to initialize blob, hr %#x.\n", hr);
494         CloseHandle(file);
495         heap_free(object);
496         return hr;
497     }
498 
499     if (!ReadFile(file, object->data, data_size, &read_size, NULL) || (read_size != data_size))
500     {
501         WARN("Failed to read file contents.\n");
502         CloseHandle(file);
503         heap_free(object->data);
504         heap_free(object);
505         return E_FAIL;
506     }
507     CloseHandle(file);
508     object->size = read_size;
509 
510     *contents = &object->ID3DBlob_iface;
511 
512     TRACE("Returning ID3DBlob %p.\n", *contents);
513 
514     return S_OK;
515 }
516 
D3DWriteBlobToFile(ID3DBlob * blob,const WCHAR * filename,BOOL overwrite)517 HRESULT WINAPI D3DWriteBlobToFile(ID3DBlob* blob, const WCHAR *filename, BOOL overwrite)
518 {
519     FIXME("blob %p, filename %s, overwrite %d\n", blob, debugstr_w(filename), overwrite);
520 
521     return E_NOTIMPL;
522 }
523