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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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