d3dcompiler: Parse ISGN in the reflection interface.
[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 static inline struct d3dcompiler_blob *impl_from_ID3DBlob(ID3DBlob *iface)
30 {
31     return CONTAINING_RECORD(iface, struct d3dcompiler_blob, ID3DBlob_iface);
32 }
33
34 /* IUnknown methods */
35
36 static HRESULT STDMETHODCALLTYPE d3dcompiler_blob_QueryInterface(ID3DBlob *iface, REFIID riid, void **object)
37 {
38     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
39
40     if (IsEqualGUID(riid, &IID_ID3D10Blob)
41             || IsEqualGUID(riid, &IID_IUnknown))
42     {
43         IUnknown_AddRef(iface);
44         *object = iface;
45         return S_OK;
46     }
47
48     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
49
50     *object = NULL;
51     return E_NOINTERFACE;
52 }
53
54 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_AddRef(ID3DBlob *iface)
55 {
56     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
57     ULONG refcount = InterlockedIncrement(&blob->refcount);
58
59     TRACE("%p increasing refcount to %u\n", blob, refcount);
60
61     return refcount;
62 }
63
64 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_Release(ID3DBlob *iface)
65 {
66     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
67     ULONG refcount = InterlockedDecrement(&blob->refcount);
68
69     TRACE("%p decreasing refcount to %u\n", blob, refcount);
70
71     if (!refcount)
72     {
73         HeapFree(GetProcessHeap(), 0, blob->data);
74         HeapFree(GetProcessHeap(), 0, blob);
75     }
76
77     return refcount;
78 }
79
80 /* ID3DBlob methods */
81
82 static void * STDMETHODCALLTYPE d3dcompiler_blob_GetBufferPointer(ID3DBlob *iface)
83 {
84     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
85
86     TRACE("iface %p\n", iface);
87
88     return blob->data;
89 }
90
91 static SIZE_T STDMETHODCALLTYPE d3dcompiler_blob_GetBufferSize(ID3DBlob *iface)
92 {
93     struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
94
95     TRACE("iface %p\n", iface);
96
97     return blob->size;
98 }
99
100 static const struct ID3D10BlobVtbl d3dcompiler_blob_vtbl =
101 {
102     /* IUnknown methods */
103     d3dcompiler_blob_QueryInterface,
104     d3dcompiler_blob_AddRef,
105     d3dcompiler_blob_Release,
106     /* ID3DBlob methods */
107     d3dcompiler_blob_GetBufferPointer,
108     d3dcompiler_blob_GetBufferSize,
109 };
110
111 HRESULT d3dcompiler_blob_init(struct d3dcompiler_blob *blob, SIZE_T data_size)
112 {
113     blob->ID3DBlob_iface.lpVtbl = &d3dcompiler_blob_vtbl;
114     blob->refcount = 1;
115     blob->size = data_size;
116
117     blob->data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
118     if (!blob->data)
119     {
120         ERR("Failed to allocate D3D blob data memory\n");
121         return E_OUTOFMEMORY;
122     }
123
124     return S_OK;
125 }
126
127 static BOOL check_blob_part(DWORD tag, D3D_BLOB_PART part)
128 {
129     BOOL add = FALSE;
130
131     switch(part)
132     {
133         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
134             if (tag == TAG_ISGN) add = TRUE;
135             break;
136
137         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
138             if (tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
139             break;
140
141         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
142             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
143             break;
144
145         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
146             if (tag == TAG_PCSG) add = TRUE;
147             break;
148
149         case D3D_BLOB_ALL_SIGNATURE_BLOB:
150             if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5 || tag == TAG_PCSG) add = TRUE;
151             break;
152
153         case D3D_BLOB_DEBUG_INFO:
154             if (tag == TAG_SDBG) add = TRUE;
155             break;
156
157         case D3D_BLOB_LEGACY_SHADER:
158             if (tag == TAG_Aon9) add = TRUE;
159             break;
160
161         case D3D_BLOB_XNA_PREPASS_SHADER:
162             if (tag == TAG_XNAP) add = TRUE;
163             break;
164
165         case D3D_BLOB_XNA_SHADER:
166             if (tag == TAG_XNAS) add = TRUE;
167             break;
168
169         default:
170             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
171             break;
172     }
173
174     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
175
176     return add;
177 }
178
179 HRESULT d3dcompiler_get_blob_part(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
180 {
181     struct dxbc src_dxbc, dst_dxbc;
182     HRESULT hr;
183     unsigned int i, count;
184
185     if (!data || !data_size || flags || !blob)
186     {
187         WARN("Invalid arguments: data %p, data_size %lu, flags %#x, blob %p\n", data, data_size, flags, blob);
188         return D3DERR_INVALIDCALL;
189     }
190
191     if (part > D3D_BLOB_TEST_COMPILE_PERF
192             || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
193     {
194         WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
195         return D3DERR_INVALIDCALL;
196     }
197
198     hr = dxbc_parse(data, data_size, &src_dxbc);
199     if (FAILED(hr))
200     {
201         WARN("Failed to parse blob part\n");
202         return hr;
203     }
204
205     hr = dxbc_init(&dst_dxbc, 0);
206     if (FAILED(hr))
207     {
208         dxbc_destroy(&src_dxbc);
209         WARN("Failed to init dxbc\n");
210         return hr;
211     }
212
213     for (i = 0; i < src_dxbc.count; ++i)
214     {
215         struct dxbc_section *section = &src_dxbc.sections[i];
216
217         if (check_blob_part(section->tag, part))
218         {
219             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
220             if (FAILED(hr))
221             {
222                 dxbc_destroy(&src_dxbc);
223                 dxbc_destroy(&dst_dxbc);
224                 WARN("Failed to add section to dxbc\n");
225                 return hr;
226             }
227         }
228     }
229
230     count = dst_dxbc.count;
231
232     switch(part)
233     {
234         case D3D_BLOB_INPUT_SIGNATURE_BLOB:
235         case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
236         case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
237         case D3D_BLOB_DEBUG_INFO:
238         case D3D_BLOB_LEGACY_SHADER:
239         case D3D_BLOB_XNA_PREPASS_SHADER:
240         case D3D_BLOB_XNA_SHADER:
241             if (count != 1) count = 0;
242             break;
243
244         case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
245             if (count != 2) count = 0;
246             break;
247
248         case D3D_BLOB_ALL_SIGNATURE_BLOB:
249             if (count != 3) count = 0;
250             break;
251
252         default:
253             FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
254             break;
255     }
256
257     if (count == 0)
258     {
259         dxbc_destroy(&src_dxbc);
260         dxbc_destroy(&dst_dxbc);
261         WARN("Nothing to write into the blob (count = 0)\n");
262         return E_FAIL;
263     }
264
265     /* some parts aren't full DXBCs, they contain only the data */
266     if (count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER || part == D3D_BLOB_XNA_PREPASS_SHADER
267             || part == D3D_BLOB_XNA_SHADER))
268     {
269         hr = D3DCreateBlob(dst_dxbc.sections[0].data_size, blob);
270         if (SUCCEEDED(hr))
271         {
272             memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.sections[0].data, dst_dxbc.sections[0].data_size);
273         }
274         else
275         {
276             WARN("Could not create blob\n");
277         }
278     }
279     else
280     {
281         hr = dxbc_write_blob(&dst_dxbc, blob);
282         if (FAILED(hr))
283         {
284             WARN("Failed to write blob part\n");
285         }
286     }
287
288     dxbc_destroy(&src_dxbc);
289     dxbc_destroy(&dst_dxbc);
290
291     return hr;
292 }
293
294 static BOOL check_blob_strip(DWORD tag, UINT flags)
295 {
296     BOOL add = TRUE;
297
298     if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
299
300     switch(tag)
301     {
302         case TAG_RDEF:
303         case TAG_STAT:
304             if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
305             break;
306
307         case TAG_SDBG:
308             if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
309             break;
310
311         default:
312             break;
313     }
314
315     TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
316
317     return add;
318 }
319
320 HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
321 {
322     struct dxbc src_dxbc, dst_dxbc;
323     HRESULT hr;
324     unsigned int i;
325
326     if (!blob)
327     {
328         WARN("NULL for blob specified\n");
329         return E_FAIL;
330     }
331
332     if (!data || !data_size)
333     {
334         WARN("Invalid arguments: data %p, data_size %lu\n", data, data_size);
335         return D3DERR_INVALIDCALL;
336     }
337
338     hr = dxbc_parse(data, data_size, &src_dxbc);
339     if (FAILED(hr))
340     {
341         WARN("Failed to parse blob part\n");
342         return hr;
343     }
344
345     /* src_dxbc.count >= dst_dxbc.count */
346     hr = dxbc_init(&dst_dxbc, src_dxbc.count);
347     if (FAILED(hr))
348     {
349         dxbc_destroy(&src_dxbc);
350         WARN("Failed to init dxbc\n");
351         return hr;
352     }
353
354     for (i = 0; i < src_dxbc.count; ++i)
355     {
356         struct dxbc_section *section = &src_dxbc.sections[i];
357
358         if (check_blob_strip(section->tag, flags))
359         {
360             hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
361             if (FAILED(hr))
362             {
363                 dxbc_destroy(&src_dxbc);
364                 dxbc_destroy(&dst_dxbc);
365                 WARN("Failed to add section to dxbc\n");
366                 return hr;
367             }
368         }
369     }
370
371     hr = dxbc_write_blob(&dst_dxbc, blob);
372     if (FAILED(hr))
373     {
374         WARN("Failed to write blob part\n");
375     }
376
377     dxbc_destroy(&src_dxbc);
378     dxbc_destroy(&dst_dxbc);
379
380     return hr;
381 }