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