gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / d3dcompiler_43 / blob.c
blobbba1c6f590b16c42be02200f7d87ecfc79bd6c4a
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 const struct vkd3d_shader_code src_dxbc = {.code = data, .size = data_size};
220 struct vkd3d_shader_dxbc_section_desc *sections;
221 struct vkd3d_shader_dxbc_desc src_dxbc_desc;
222 struct vkd3d_shader_code dst_dxbc;
223 unsigned int section_count, i;
224 HRESULT hr;
225 int ret;
227 if (!data || data_size < DXBC_HEADER_SIZE || flags || !blob)
229 WARN("Invalid arguments: data %p, data_size %Iu, flags %#x, blob %p.\n", data, data_size, flags, blob);
230 return D3DERR_INVALIDCALL;
233 if (part > D3D_BLOB_TEST_COMPILE_PERF
234 || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER))
236 WARN("Invalid D3D_BLOB_PART: part %s\n", debug_d3dcompiler_d3d_blob_part(part));
237 return D3DERR_INVALIDCALL;
240 if ((ret = vkd3d_shader_parse_dxbc(&src_dxbc, 0, &src_dxbc_desc, NULL)) < 0)
242 WARN("Failed to parse source data, ret %d.\n", ret);
243 return E_FAIL;
246 if (!(sections = calloc(src_dxbc_desc.section_count, sizeof(*sections))))
248 ERR("Failed to allocate sections memory.\n");
249 vkd3d_shader_free_dxbc(&src_dxbc_desc);
250 return E_OUTOFMEMORY;
253 for (i = 0, section_count = 0; i < src_dxbc_desc.section_count; ++i)
255 const struct vkd3d_shader_dxbc_section_desc *src_section = &src_dxbc_desc.sections[i];
257 if (check_blob_part(src_section->tag, part))
258 sections[section_count++] = *src_section;
261 switch(part)
263 case D3D_BLOB_INPUT_SIGNATURE_BLOB:
264 case D3D_BLOB_OUTPUT_SIGNATURE_BLOB:
265 case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB:
266 case D3D_BLOB_DEBUG_INFO:
267 case D3D_BLOB_LEGACY_SHADER:
268 case D3D_BLOB_XNA_PREPASS_SHADER:
269 case D3D_BLOB_XNA_SHADER:
270 if (section_count != 1)
271 section_count = 0;
272 break;
274 case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB:
275 if (section_count != 2)
276 section_count = 0;
277 break;
279 case D3D_BLOB_ALL_SIGNATURE_BLOB:
280 if (section_count != 3)
281 section_count = 0;
282 break;
284 default:
285 FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3dcompiler_d3d_blob_part(part));
286 break;
289 if (!section_count)
291 WARN("Nothing to write into the blob.\n");
292 hr = E_FAIL;
293 goto done;
296 /* some parts aren't full DXBCs, they contain only the data */
297 if (section_count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER
298 || part == D3D_BLOB_XNA_PREPASS_SHADER || part == D3D_BLOB_XNA_SHADER))
300 dst_dxbc = sections[0].data;
302 else if ((ret = vkd3d_shader_serialize_dxbc(section_count, sections, &dst_dxbc, NULL) < 0))
304 WARN("Failed to serialise DXBC, ret %d.\n", ret);
305 hr = E_FAIL;
306 goto done;
309 if (FAILED(hr = D3DCreateBlob(dst_dxbc.size, blob)))
310 WARN("Failed to create blob, hr %#lx.\n", hr);
311 else
312 memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.code, dst_dxbc.size);
313 if (dst_dxbc.code != sections[0].data.code)
314 vkd3d_shader_free_shader_code(&dst_dxbc);
316 done:
317 free(sections);
318 vkd3d_shader_free_dxbc(&src_dxbc_desc);
320 return hr;
323 static BOOL check_blob_strip(DWORD tag, UINT flags)
325 BOOL add = TRUE;
327 if (flags & D3DCOMPILER_STRIP_TEST_BLOBS) FIXME("Unhandled flag D3DCOMPILER_STRIP_TEST_BLOBS.\n");
329 switch(tag)
331 case TAG_RDEF:
332 case TAG_STAT:
333 if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) add = FALSE;
334 break;
336 case TAG_SDBG:
337 if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) add = FALSE;
338 break;
340 default:
341 break;
344 TRACE("%s tag %s\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4));
346 return add;
349 static HRESULT d3dcompiler_strip_shader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob)
351 const struct vkd3d_shader_code src_dxbc = {.code = data, .size = data_size};
352 struct vkd3d_shader_dxbc_section_desc *sections;
353 struct vkd3d_shader_dxbc_desc src_dxbc_desc;
354 struct vkd3d_shader_code dst_dxbc;
355 unsigned int section_count, i;
356 HRESULT hr;
357 int ret;
359 if (!blob)
361 WARN("NULL for blob specified\n");
362 return E_FAIL;
365 if (!data || data_size < DXBC_HEADER_SIZE)
367 WARN("Invalid arguments: data %p, data_size %Iu.\n", data, data_size);
368 return D3DERR_INVALIDCALL;
371 if ((ret = vkd3d_shader_parse_dxbc(&src_dxbc, 0, &src_dxbc_desc, NULL)) < 0)
373 WARN("Failed to parse source data, ret %d.\n", ret);
374 return E_FAIL;
377 /* src_dxbc.count >= dst_dxbc.count */
378 if (!(sections = calloc(src_dxbc_desc.section_count, sizeof(*sections))))
380 ERR("Failed to allocate sections memory.\n");
381 vkd3d_shader_free_dxbc(&src_dxbc_desc);
382 return E_OUTOFMEMORY;
385 for (i = 0, section_count = 0; i < src_dxbc_desc.section_count; ++i)
387 const struct vkd3d_shader_dxbc_section_desc *src_section = &src_dxbc_desc.sections[i];
389 if (check_blob_strip(src_section->tag, flags))
390 sections[section_count++] = *src_section;
393 if ((ret = vkd3d_shader_serialize_dxbc(section_count, sections, &dst_dxbc, NULL) < 0))
395 WARN("Failed to serialise DXBC, ret %d.\n", ret);
396 hr = E_FAIL;
397 goto done;
400 if (FAILED(hr = D3DCreateBlob(dst_dxbc.size, blob)))
401 WARN("Failed to create blob, hr %#lx.\n", hr);
402 else
403 memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.code, dst_dxbc.size);
404 vkd3d_shader_free_shader_code(&dst_dxbc);
406 done:
407 free(sections);
408 vkd3d_shader_free_dxbc(&src_dxbc_desc);
410 return hr;
413 HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob)
415 TRACE("data %p, data_size %Iu, part %s, flags %#x, blob %p.\n", data,
416 data_size, debug_d3dcompiler_d3d_blob_part(part), flags, blob);
418 return d3dcompiler_get_blob_part(data, data_size, part, flags, blob);
421 HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
423 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
425 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob);
428 HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
430 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
432 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob);
435 HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob)
437 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
439 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob);
442 HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob)
444 TRACE("data %p, data_size %Iu, blob %p.\n", data, data_size, blob);
446 return d3dcompiler_get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob);
449 HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3D10Blob **blob)
451 TRACE("data %p, data_size %Iu, flags %#x, blob %p.\n", data, data_size, flags, blob);
453 return d3dcompiler_strip_shader(data, data_size, flags, blob);
456 HRESULT WINAPI D3DReadFileToBlob(const WCHAR *filename, ID3DBlob **contents)
458 struct d3dcompiler_blob *object;
459 SIZE_T data_size;
460 DWORD read_size;
461 HANDLE file;
462 HRESULT hr;
464 TRACE("filename %s, contents %p.\n", debugstr_w(filename), contents);
466 file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
467 if (file == INVALID_HANDLE_VALUE)
468 return HRESULT_FROM_WIN32(GetLastError());
470 data_size = GetFileSize(file, NULL);
471 if (data_size == INVALID_FILE_SIZE)
473 CloseHandle(file);
474 return HRESULT_FROM_WIN32(GetLastError());
477 if (!(object = heap_alloc_zero(sizeof(*object))))
479 CloseHandle(file);
480 return E_OUTOFMEMORY;
483 if (FAILED(hr = d3dcompiler_blob_init(object, data_size)))
485 WARN("Failed to initialise blob, hr %#lx.\n", hr);
486 CloseHandle(file);
487 heap_free(object);
488 return hr;
491 if (!ReadFile(file, object->data, data_size, &read_size, NULL) || (read_size != data_size))
493 WARN("Failed to read file contents.\n");
494 CloseHandle(file);
495 heap_free(object->data);
496 heap_free(object);
497 return E_FAIL;
499 CloseHandle(file);
500 object->size = read_size;
502 *contents = &object->ID3DBlob_iface;
504 TRACE("Returning ID3DBlob %p.\n", *contents);
506 return S_OK;
509 HRESULT WINAPI D3DWriteBlobToFile(ID3DBlob *blob, const WCHAR *filename, BOOL overwrite)
511 DWORD written_size;
512 SIZE_T data_size;
513 HANDLE file;
514 BOOL ret;
516 TRACE("blob %p, filename %s, overwrite %#x.\n", blob, debugstr_w(filename), overwrite);
518 file = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, overwrite ? CREATE_ALWAYS : CREATE_NEW,
519 FILE_ATTRIBUTE_NORMAL, NULL);
520 if (file == INVALID_HANDLE_VALUE)
521 return HRESULT_FROM_WIN32(GetLastError());
523 data_size = ID3D10Blob_GetBufferSize(blob);
524 ret = WriteFile(file, ID3D10Blob_GetBufferPointer(blob), data_size, &written_size, NULL);
525 CloseHandle(file);
526 if (!ret || data_size != written_size)
528 WARN("Failed to write blob contents.\n");
529 return E_FAIL;
532 return S_OK;