/* * 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; }