diff --git a/include/private/vkd3d_debug.h b/include/private/vkd3d_debug.h index 663fc311..c5b6cced 100644 --- a/include/private/vkd3d_debug.h +++ b/include/private/vkd3d_debug.h @@ -89,6 +89,10 @@ const char *debugstr_w(const WCHAR *wstr, size_t wchar_size); #define TRACE_ON() (vkd3d_dbg_get_level() == VKD3D_DBG_LEVEL_TRACE) #endif +#ifndef WARN_ON +#define WARN_ON() (vkd3d_dbg_get_level() >= VKD3D_DBG_LEVEL_WARN) +#endif + #define FIXME_ONCE VKD3D_DBG_LOG_ONCE(FIXME, WARN) #define VKD3D_DEBUG_ENV_NAME(name) const char *const vkd3d_dbg_env_name = name diff --git a/include/vkd3d_d3dcompiler.h b/include/vkd3d_d3dcompiler.h index 1975f4f9..872a90bb 100644 --- a/include/vkd3d_d3dcompiler.h +++ b/include/vkd3d_d3dcompiler.h @@ -79,6 +79,7 @@ HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filen const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, ID3DBlob **error_messages); HRESULT WINAPI D3DCreateBlob(SIZE_T size, ID3DBlob **blob); +HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T data_size, UINT flags, const char *comments, ID3DBlob **blob); HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob); HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob); HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob); @@ -89,5 +90,8 @@ HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection); HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob); +typedef HRESULT (WINAPI *pD3DDisassemble)(const void *data, SIZE_T data_size, + UINT flags, const char *comments, ID3DBlob **blob); + #endif /* __D3DCOMPILER_H__ */ #endif /* __VKD3D_D3DCOMPILER_H */ diff --git a/include/vkd3d_utils.h b/include/vkd3d_utils.h index adcac5fc..7616a3f3 100644 --- a/include/vkd3d_utils.h +++ b/include/vkd3d_utils.h @@ -117,6 +117,8 @@ VKD3D_UTILS_API HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_ VKD3D_UTILS_API HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob); /** \since 1.11 */ +VKD3D_UTILS_API HRESULT WINAPI D3DDisassemble(const void *data, + SIZE_T data_size, UINT flags, const char *comments, ID3DBlob **blob); VKD3D_UTILS_API HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection); #ifdef __cplusplus diff --git a/libs/vkd3d-utils/vkd3d_utils.map b/libs/vkd3d-utils/vkd3d_utils.map index 8dad9cc3..c422c0ca 100644 --- a/libs/vkd3d-utils/vkd3d_utils.map +++ b/libs/vkd3d-utils/vkd3d_utils.map @@ -11,6 +11,7 @@ global: D3DCompile; D3DCompile2; D3DCreateBlob; + D3DDisassemble; D3DGetBlobPart; D3DGetDebugInfo; D3DGetInputAndOutputSignatureBlob; diff --git a/libs/vkd3d-utils/vkd3d_utils_main.c b/libs/vkd3d-utils/vkd3d_utils_main.c index 349523e0..f847b250 100644 --- a/libs/vkd3d-utils/vkd3d_utils_main.c +++ b/libs/vkd3d-utils/vkd3d_utils_main.c @@ -928,3 +928,75 @@ void vkd3d_utils_set_log_callback(PFN_vkd3d_log callback) vkd3d_set_log_callback(callback); vkd3d_dbg_set_log_callback(callback); } + +HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T data_size, + UINT flags, const char *comments, ID3DBlob **blob) +{ + enum vkd3d_shader_source_type source_type; + struct vkd3d_shader_compile_info info; + struct vkd3d_shader_code output; + const char *p, *q, *end; + char *messages; + HRESULT hr; + int ret; + + static const struct vkd3d_shader_compile_option options[] = + { + {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_10}, + }; + + TRACE("data %p, data_size %lu, flags %#x, comments %p, blob %p.\n", + data, data_size, flags, comments, blob); + + if (flags) + FIXME("Ignoring flags %#x.\n", flags); + + if (comments) + FIXME("Ignoring comments %s.\n", debugstr_a(comments)); + + if (!data_size) + return E_INVALIDARG; + + if (data_size >= sizeof(uint32_t) && *(uint32_t *)data == TAG_DXBC) + source_type = VKD3D_SHADER_SOURCE_DXBC_TPF; + else + source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE; + + info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; + info.next = NULL; + info.source.code = data; + info.source.size = data_size; + info.source_type = source_type; + info.target_type = VKD3D_SHADER_TARGET_D3D_ASM; + info.options = options; + info.option_count = ARRAY_SIZE(options); + info.log_level = VKD3D_SHADER_LOG_INFO; + info.source_name = NULL; + + ret = vkd3d_shader_compile(&info, &output, &messages); + if (messages && *messages && WARN_ON()) + { + WARN("Compiler log:\n"); + for (p = messages, end = p + strlen(p); p < end; p = q) + { + if (!(q = memchr(p, '\n', end - p))) + q = end; + else + ++q; + WARN(" %.*s", (int)(q - p), p); + } + WARN("\n"); + } + vkd3d_shader_free_messages(messages); + + if (ret < 0) + { + WARN("Failed to disassemble shader, ret %d.\n", ret); + return hresult_from_vkd3d_result(ret); + } + + if (FAILED(hr = vkd3d_blob_create((void *)output.code, output.size, blob))) + vkd3d_shader_free_shader_code(&output); + + return hr; +} diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index 6f76cda5..272b8aca 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -1514,6 +1514,98 @@ static void test_signature_reflection(void) } } +static void test_disassemble_shader(void) +{ + ID3DBlob *blob; + int hr; + + /* A Direct3D 8 vertex shader without dcl_ instructions. */ + static const uint32_t vs_1_1[] = + { + 0xfffe0101, /* vs_1_1 */ + 0x00000005, 0x800f0000, 0x90000000, 0xa0e40000, /* mul r0, v0.x, c0 */ + 0x00000004, 0x800f0000, 0x90550000, 0xa0e40001, 0x80e40000, /* mad r0, v0.y, c1, r0 */ + 0x00000004, 0x800f0000, 0x90aa0000, 0xa0e40002, 0x80e40000, /* mad r0, v0.z, c2, r0 */ + 0x00000004, 0xc00f0000, 0x90ff0000, 0xa0e40003, 0x80e40000, /* mad oPos, v0.w, c3, r0 */ + 0x0000ffff, /* end */ + }; + + static const uint32_t vs_2_0[] = + { + 0xfffe0200, /* vs_2_0 */ + 0x0200001f, 0x80000000, 0x900f0000, /* dcl_position v0 */ + 0x0200001f, 0x80000003, 0x900f0001, /* dcl_normal v1 */ + 0x0200001f, 0x8001000a, 0x900f0002, /* dcl_color1 v2 */ + 0x0200001f, 0x80000005, 0x900f0003, /* dcl_texcoord0 v3 */ + 0x02000001, 0xc00f0000, 0x90e40000, /* mov oPos, v0 */ + 0x02000001, 0xd00f0001, 0x90e40002, /* mov oD1, v2 */ + 0x02000001, 0xe0070000, 0x90e40003, /* mov oT0.xyz, v3 */ + 0x02000001, 0xc00f0001, 0x90ff0002, /* mov oFog, v2.w */ + 0x02000001, 0xc00f0002, 0x90ff0001, /* mov oPts, v1.w */ + 0x0000ffff, /* end */ + }; + + /* A shader model 3 vertex shader without dcl_ instructions. */ + static const uint32_t vs_3_0[] = + { + 0xfffe0300, /* vs_3_0 */ + 0x02000001, 0xe00f0000, 0x90e40000, /* mov o0, v0 */ + 0x0000ffff, /* end */ + }; + + /* A "shader model 4" d3dbc vertex shader. */ + static const uint32_t vs_4_0[] = + { + 0xfffe0400, /* vs_4_0 */ + 0x02000001, 0xe00f0000, 0x90e40000, /* mov o0, v0 */ + 0x0000ffff, /* end */ + }; + + /* An actual shader model 4 dxbc-tpf vertex shader. */ + static const uint32_t vs_4_0_dxbc[] = + { +#if 0 + float4 main(float4 position : POSITION) : SV_POSITION + { + return position; + } +#endif + 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003, + 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00, + 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003, + 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040, + 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, + 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e, + }; + + hr = D3DDisassemble(vs_1_1, 0, 0, NULL, &blob); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = D3DDisassemble(vs_1_1, sizeof(vs_1_1), 0, NULL, &blob); + todo ok(hr == S_OK, "Got hr %#x.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Blob_Release(blob); + + hr = D3DDisassemble(vs_2_0, sizeof(vs_2_0), 0, NULL, &blob); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ID3D10Blob_Release(blob); + + hr = D3DDisassemble(vs_3_0, sizeof(vs_3_0), 0, NULL, &blob); + todo ok(hr == S_OK, "Got hr %#x.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Blob_Release(blob); + + hr = D3DDisassemble(vs_4_0, sizeof(vs_4_0), 0, NULL, &blob); + todo ok(hr == S_OK, "Got hr %#x.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Blob_Release(blob); + + hr = D3DDisassemble(vs_4_0_dxbc, sizeof(vs_4_0_dxbc), 0, NULL, &blob); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ID3D10Blob_Release(blob); +} + START_TEST(hlsl_d3d12) { parse_args(argc, argv); @@ -1525,4 +1617,5 @@ START_TEST(hlsl_d3d12) run_test(test_create_blob); run_test(test_get_blob_part); run_test(test_signature_reflection); + run_test(test_disassemble_shader); }