| /* |
| * Copyright 2008-2009 Henri Verbeet for CodeWeavers |
| * Copyright 2010 Rico Schüller |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include "d3dcompiler_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(d3dcompiler); |
| |
| #define WINE_D3DCOMPILER_TO_STR(x) case x: return #x |
| |
| const char *debug_d3dcompiler_d3d_blob_part(D3D_BLOB_PART part) |
| { |
| switch(part) |
| { |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_INPUT_SIGNATURE_BLOB); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_OUTPUT_SIGNATURE_BLOB); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_ALL_SIGNATURE_BLOB); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_DEBUG_INFO); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_LEGACY_SHADER); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_XNA_PREPASS_SHADER); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_XNA_SHADER); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_ALTERNATE_SHADER); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_COMPILE_DETAILS); |
| WINE_D3DCOMPILER_TO_STR(D3D_BLOB_TEST_COMPILE_PERF); |
| default: |
| FIXME("Unrecognized D3D_BLOB_PART %#x\n", part); |
| return "unrecognized"; |
| } |
| } |
| |
| #undef WINE_D3DCOMPILER_TO_STR |
| |
| void skip_dword_unknown(const char **ptr, unsigned int count) |
| { |
| unsigned int i; |
| DWORD d; |
| |
| FIXME("Skipping %u unknown DWORDs:\n", count); |
| for (i = 0; i < count; ++i) |
| { |
| read_dword(ptr, &d); |
| FIXME("\t0x%08x\n", d); |
| } |
| } |
| |
| void write_dword_unknown(char **ptr, DWORD d) |
| { |
| FIXME("Writing unknown DWORD 0x%08x\n", d); |
| write_dword(ptr, d); |
| } |
| |
| HRESULT dxbc_add_section(struct dxbc *dxbc, DWORD tag, const char *data, DWORD data_size) |
| { |
| TRACE("dxbc %p, tag %s, size %#x.\n", dxbc, debugstr_an((const char *)&tag, 4), data_size); |
| |
| if (dxbc->count >= dxbc->size) |
| { |
| struct dxbc_section *new_sections; |
| DWORD new_size = dxbc->size << 1; |
| |
| new_sections = HeapReAlloc(GetProcessHeap(), 0, dxbc->sections, new_size * sizeof(*dxbc->sections)); |
| if (!new_sections) |
| { |
| ERR("Failed to allocate dxbc section memory\n"); |
| return E_OUTOFMEMORY; |
| } |
| |
| dxbc->sections = new_sections; |
| dxbc->size = new_size; |
| } |
| |
| dxbc->sections[dxbc->count].tag = tag; |
| dxbc->sections[dxbc->count].data_size = data_size; |
| dxbc->sections[dxbc->count].data = data; |
| ++dxbc->count; |
| |
| return S_OK; |
| } |
| |
| HRESULT dxbc_init(struct dxbc *dxbc, UINT size) |
| { |
| TRACE("dxbc %p, size %u.\n", dxbc, size); |
| |
| /* use a good starting value for the size if none specified */ |
| if (!size) size = 2; |
| |
| dxbc->sections = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*dxbc->sections)); |
| if (!dxbc->sections) |
| { |
| ERR("Failed to allocate dxbc section memory\n"); |
| return E_OUTOFMEMORY; |
| } |
| |
| dxbc->size = size; |
| dxbc->count = 0; |
| |
| return S_OK; |
| } |
| |
| HRESULT dxbc_parse(const char *data, SIZE_T data_size, struct dxbc *dxbc) |
| { |
| const char *ptr = data; |
| HRESULT hr; |
| unsigned int i; |
| DWORD tag, total_size, chunk_count; |
| |
| if (!data) |
| { |
| WARN("No data supplied.\n"); |
| return E_FAIL; |
| } |
| |
| read_dword(&ptr, &tag); |
| TRACE("tag: %s.\n", debugstr_an((const char *)&tag, 4)); |
| |
| if (tag != TAG_DXBC) |
| { |
| WARN("Wrong tag.\n"); |
| return E_FAIL; |
| } |
| |
| /* checksum? */ |
| skip_dword_unknown(&ptr, 4); |
| |
| skip_dword_unknown(&ptr, 1); |
| |
| read_dword(&ptr, &total_size); |
| TRACE("total size: %#x\n", total_size); |
| |
| if (data_size != total_size) |
| { |
| WARN("Wrong size supplied.\n"); |
| return D3DERR_INVALIDCALL; |
| } |
| |
| read_dword(&ptr, &chunk_count); |
| TRACE("chunk count: %#x\n", chunk_count); |
| |
| hr = dxbc_init(dxbc, chunk_count); |
| if (FAILED(hr)) |
| { |
| WARN("Failed to init dxbc\n"); |
| return hr; |
| } |
| |
| for (i = 0; i < chunk_count; ++i) |
| { |
| DWORD chunk_tag, chunk_size; |
| const char *chunk_ptr; |
| DWORD chunk_offset; |
| |
| read_dword(&ptr, &chunk_offset); |
| TRACE("chunk %u at offset %#x\n", i, chunk_offset); |
| |
| chunk_ptr = data + chunk_offset; |
| |
| read_dword(&chunk_ptr, &chunk_tag); |
| read_dword(&chunk_ptr, &chunk_size); |
| |
| hr = dxbc_add_section(dxbc, chunk_tag, chunk_ptr, chunk_size); |
| if (FAILED(hr)) |
| { |
| WARN("Failed to add section to dxbc\n"); |
| return hr; |
| } |
| } |
| |
| return hr; |
| } |
| |
| void dxbc_destroy(struct dxbc *dxbc) |
| { |
| TRACE("dxbc %p.\n", dxbc); |
| |
| HeapFree(GetProcessHeap(), 0, dxbc->sections); |
| } |
| |
| HRESULT dxbc_write_blob(struct dxbc *dxbc, ID3DBlob **blob) |
| { |
| DWORD size = 32, offset = size + 4 * dxbc->count; |
| ID3DBlob *object; |
| HRESULT hr; |
| char *ptr; |
| unsigned int i; |
| |
| TRACE("dxbc %p, blob %p.\n", dxbc, blob); |
| |
| for (i = 0; i < dxbc->count; ++i) |
| { |
| size += 12 + dxbc->sections[i].data_size; |
| } |
| |
| hr = D3DCreateBlob(size, &object); |
| if (FAILED(hr)) |
| { |
| WARN("Failed to create blob\n"); |
| return hr; |
| } |
| |
| ptr = ID3D10Blob_GetBufferPointer(object); |
| |
| write_dword(&ptr, TAG_DXBC); |
| |
| /* signature(?) */ |
| write_dword_unknown(&ptr, 0); |
| write_dword_unknown(&ptr, 0); |
| write_dword_unknown(&ptr, 0); |
| write_dword_unknown(&ptr, 0); |
| |
| /* seems to be always 1 */ |
| write_dword_unknown(&ptr, 1); |
| |
| /* DXBC size */ |
| write_dword(&ptr, size); |
| |
| /* chunk count */ |
| write_dword(&ptr, dxbc->count); |
| |
| /* write the chunk offsets */ |
| for (i = 0; i < dxbc->count; ++i) |
| { |
| write_dword(&ptr, offset); |
| offset += 8 + dxbc->sections[i].data_size; |
| } |
| |
| /* write the chunks */ |
| for (i = 0; i < dxbc->count; ++i) |
| { |
| write_dword(&ptr, dxbc->sections[i].tag); |
| write_dword(&ptr, dxbc->sections[i].data_size); |
| memcpy(ptr, dxbc->sections[i].data, dxbc->sections[i].data_size); |
| ptr += dxbc->sections[i].data_size; |
| } |
| |
| TRACE("Created ID3DBlob %p\n", object); |
| |
| *blob = object; |
| |
| return S_OK; |
| } |