d3dcompiler: Check for minimum bytecode size in d3dcompiler_strip_shader().
[wine.git] / dlls / d3dcompiler_43 / blob.c
blob3477469f9c3ba4f25d3125c0b864fa4fae75e6ed
1 /*
2 * Direct3D blob file
4 * Copyright 2010 Rico Schüller
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.
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.
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
22 #include "d3dcompiler_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler);
26 struct d3dcompiler_blob
28 ID3DBlob ID3DBlob_iface;
29 LONG refcount;
31 SIZE_T size;
32 void *data;
35 static inline struct d3dcompiler_blob *impl_from_ID3DBlob(ID3DBlob *iface)
37 return CONTAINING_RECORD(iface, struct d3dcompiler_blob, ID3DBlob_iface);
40 /* IUnknown methods */
42 static HRESULT STDMETHODCALLTYPE d3dcompiler_blob_QueryInterface(ID3DBlob *iface, REFIID riid, void **object)
44 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
46 if (IsEqualGUID(riid, &IID_ID3D10Blob)
47 || IsEqualGUID(riid, &IID_IUnknown))
49 IUnknown_AddRef(iface);
50 *object = iface;
51 return S_OK;
54 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
56 *object = NULL;
57 return E_NOINTERFACE;
60 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_AddRef(ID3DBlob *iface)
62 struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
63 ULONG refcount = InterlockedIncrement(&blob->refcount);
65 TRACE("%p increasing refcount to %lu.\n", blob, refcount);
67 return refcount;
70 static ULONG STDMETHODCALLTYPE d3dcompiler_blob_Release(ID3DBlob *iface)
72 struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
73 ULONG refcount = InterlockedDecrement(&blob->refcount);
75 TRACE("%p decreasing refcount to %lu.\n", blob, refcount);
77 if (!refcount)
79 HeapFree(GetProcessHeap(), 0, blob->data);
80 HeapFree(GetProcessHeap(), 0, blob);
83 return refcount;
86 /* ID3DBlob methods */
88 static void * STDMETHODCALLTYPE d3dcompiler_blob_GetBufferPointer(ID3DBlob *iface)
90 struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
92 TRACE("iface %p\n", iface);
94 return blob->data;
97 static SIZE_T STDMETHODCALLTYPE d3dcompiler_blob_GetBufferSize(ID3DBlob *iface)
99 struct d3dcompiler_blob *blob = impl_from_ID3DBlob(iface);
101 TRACE("iface %p\n", iface);
103 return blob->size;
106 static const struct ID3D10BlobVtbl d3dcompiler_blob_vtbl =
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,
117 static HRESULT d3dcompiler_blob_init(struct d3dcompiler_blob *blob, SIZE_T data_size)
119 blob->ID3DBlob_iface.lpVtbl = &d3dcompiler_blob_vtbl;
120 blob->refcount = 1;
121 blob->size = data_size;
123 blob->data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
124 if (!blob->data)
126 ERR("Failed to allocate D3D blob data memory\n");
127 return E_OUTOFMEMORY;
130 return S_OK;
133 HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob)
135 struct d3dcompiler_blob *object;
136 HRESULT hr;
138 TRACE("data_size %Iu, blob %p.\n", data_size, blob);
140 if (!blob)
142 WARN("Invalid blob specified.\n");
143 return D3DERR_INVALIDCALL;
146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
147 if (!object)
148 return E_OUTOFMEMORY;
150 hr = d3dcompiler_blob_init(object, data_size);
151 if (FAILED(hr))
153 WARN("Failed to initialize blob, hr %#lx.\n", hr);
154 HeapFree(GetProcessHeap(), 0, object);
155 return hr;
158 *blob = &object->ID3DBlob_iface;
160 TRACE("Created ID3DBlob %p\n", *blob);
162 return S_OK;
165 static BOOL check_blob_part(DWORD tag, D3D_BLOB_PART part)
167 BOOL add = FALSE;
169 switch(part)
171 case D3D_BLOB_INPUT_SIGNATURE_BLOB:
172 if (tag == TAG_ISGN) add = TRUE;
173 break;
175 case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
176 if (tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
177 break;
179 case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
180 if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) add = TRUE;
181 break;
183 case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
184 if (tag == TAG_PCSG) add = TRUE;
185 break;
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;
191 case D3D_BLOB_DEBUG_INFO:
192 if (tag == TAG_SDBG) add = TRUE;
193 break;
195 case D3D_BLOB_LEGACY_SHADER:
196 if (tag == TAG_Aon9) add = TRUE;
197 break;
199 case D3D_BLOB_XNA_PREPASS_SHADER:
200 if (tag == TAG_XNAP) add = TRUE;
201 break;
203 case D3D_BLOB_XNA_SHADER:
204 if (tag == TAG_XNAS) add = TRUE;
205 break;
207 default:
208 FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
209 break;
212 TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
214 return add;
217 static HRESULT d3dcompiler_get_blob_part(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
219 struct dxbc src_dxbc, dst_dxbc;
220 HRESULT hr;
221 unsigned int i, count;
223 if (!data || data_size < DXBC_HEADER_SIZE || flags || !blob)
225 WARN("Invalid arguments: data %p, data_size %Iu, flags %#x, blob %p.\n", data, data_size, flags, blob);
226 return D3DERR_INVALIDCALL;
229 if (part > D3D_BLOB_TEST_COMPILE_PERF
230 || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
232 WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
233 return D3DERR_INVALIDCALL;
236 hr = dxbc_parse(data, data_size, &src_dxbc);
237 if (FAILED(hr))
239 WARN("Failed to parse blob part\n");
240 return hr;
243 hr = dxbc_init(&dst_dxbc, 0);
244 if (FAILED(hr))
246 dxbc_destroy(&src_dxbc);
247 WARN("Failed to init dxbc\n");
248 return hr;
251 for (i = 0; i < src_dxbc.count; ++i)
253 struct dxbc_section *section = &src_dxbc.sections[i];
255 if (check_blob_part(section->tag, part))
257 hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
258 if (FAILED(hr))
260 dxbc_destroy(&src_dxbc);
261 dxbc_destroy(&dst_dxbc);
262 WARN("Failed to add section to dxbc\n");
263 return hr;
268 count = dst_dxbc.count;
270 switch(part)
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;
282 case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
283 if (count != 2) count = 0;
284 break;
286 case D3D_BLOB_ALL_SIGNATURE_BLOB:
287 if (count != 3) count = 0;
288 break;
290 default:
291 FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
292 break;
295 if (count == 0)
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;
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))
307 hr = D3DCreateBlob(dst_dxbc.sections[0].data_size, blob);
308 if (SUCCEEDED(hr))
310 memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.sections[0].data, dst_dxbc.sections[0].data_size);
312 else
314 WARN("Could not create blob\n");
317 else
319 hr = dxbc_write_blob(&dst_dxbc, blob);
320 if (FAILED(hr))
322 WARN("Failed to write blob part\n");
326 dxbc_destroy(&src_dxbc);
327 dxbc_destroy(&dst_dxbc);
329 return hr;
332 static BOOL check_blob_strip(DWORD tag, UINT flags)
334 BOOL add = TRUE;
336 if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
338 switch(tag)
340 case TAG_RDEF:
341 case TAG_STAT:
342 if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
343 break;
345 case TAG_SDBG:
346 if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
347 break;
349 default:
350 break;
353 TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
355 return add;
358 static HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
360 struct dxbc src_dxbc, dst_dxbc;
361 HRESULT hr;
362 unsigned int i;
364 if (!blob)
366 WARN("NULL for blob specified\n");
367 return E_FAIL;
370 if (!data || data_size < DXBC_HEADER_SIZE)
372 WARN("Invalid arguments: data %p, data_size %Iu.\n", data, data_size);
373 return D3DERR_INVALIDCALL;
376 hr = dxbc_parse(data, data_size, &src_dxbc);
377 if (FAILED(hr))
379 WARN("Failed to parse blob part\n");
380 return hr;
383 /* src_dxbc.count >= dst_dxbc.count */
384 hr = dxbc_init(&dst_dxbc, src_dxbc.count);
385 if (FAILED(hr))
387 dxbc_destroy(&src_dxbc);
388 WARN("Failed to init dxbc\n");
389 return hr;
392 for (i = 0; i < src_dxbc.count; ++i)
394 struct dxbc_section *section = &src_dxbc.sections[i];
396 if (check_blob_strip(section->tag, flags))
398 hr = dxbc_add_section(&dst_dxbc, section->tag, section->data, section->data_size);
399 if (FAILED(hr))
401 dxbc_destroy(&src_dxbc);
402 dxbc_destroy(&dst_dxbc);
403 WARN("Failed to add section to dxbc\n");
404 return hr;
409 hr = dxbc_write_blob(&dst_dxbc, blob);
410 if (FAILED(hr))
412 WARN("Failed to write blob part\n");
415 dxbc_destroy(&src_dxbc);
416 dxbc_destroy(&dst_dxbc);
418 return hr;
421 HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
423 TRACE("data %p, data_size %Iu, part %s, flags %#x, blob %p.\n", data,
424 data_size, debug_d3dcompiler_d3d_blob_part(part), flags, blob);
426 return d3dcompiler_get_blob_part(data, data_size, part, flags, blob);
429 HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
431 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
433 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob);
436 HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
438 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
440 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob);
443 HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
445 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
447 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob);
450 HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob)
452 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
454 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob);
457 HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3D10Blob **blob)
459 TRACE("data %p, data_size %Iu, flags %#x, blob %p.\n", data, data_size, flags, blob);
461 return d3dcompiler_strip_shader(data, data_size, flags, blob);
464 HRESULT WINAPI D3DReadFileToBlob(const WCHAR *filename, ID3DBlob **contents)
466 struct d3dcompiler_blob *object;
467 SIZE_T data_size;
468 DWORD read_size;
469 HANDLE file;
470 HRESULT hr;
472 TRACE("filename %s, contents %p.\n", debugstr_w(filename), contents);
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());
478 data_size = GetFileSize(file, NULL);
479 if (data_size == INVALID_FILE_SIZE)
481 CloseHandle(file);
482 return HRESULT_FROM_WIN32(GetLastError());
485 if (!(object = heap_alloc_zero(sizeof(*object))))
487 CloseHandle(file);
488 return E_OUTOFMEMORY;
491 if (FAILED(hr = d3dcompiler_blob_init(object, data_size)))
493 WARN("Failed to initialise blob, hr %#lx.\n", hr);
494 CloseHandle(file);
495 heap_free(object);
496 return hr;
499 if (!ReadFile(file, object->data, data_size, &read_size, NULL) || (read_size != data_size))
501 WARN("Failed to read file contents.\n");
502 CloseHandle(file);
503 heap_free(object->data);
504 heap_free(object);
505 return E_FAIL;
507 CloseHandle(file);
508 object->size = read_size;
510 *contents = &object->ID3DBlob_iface;
512 TRACE("Returning ID3DBlob %p.\n", *contents);
514 return S_OK;
517 HRESULT WINAPI D3DWriteBlobToFile(ID3DBlob *blob, const WCHAR *filename, BOOL overwrite)
519 DWORD written_size;
520 SIZE_T data_size;
521 HANDLE file;
522 BOOL ret;
524 TRACE("blob %p, filename %s, overwrite %#x.\n", blob, debugstr_w(filename), overwrite);
526 file = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, overwrite ? CREATE_ALWAYS : CREATE_NEW,
527 FILE_ATTRIBUTE_NORMAL, NULL);
528 if (file == INVALID_HANDLE_VALUE)
529 return HRESULT_FROM_WIN32(GetLastError());
531 data_size = ID3D10Blob_GetBufferSize(blob);
532 ret = WriteFile(file, ID3D10Blob_GetBufferPointer(blob), data_size, &written_size, NULL);
533 CloseHandle(file);
534 if (!ret || data_size != written_size)
536 WARN("Failed to write blob contents.\n");
537 return E_FAIL;
540 return S_OK;