From: Elizabeth Figura zfigura@codeweavers.com
--- configure.ac | 10 +- dlls/wined3d/wined3d_main.c | 4 +- libs/vkd3d/Makefile.in | 2 + libs/vkd3d/include/vkd3d_utils.h | 155 +++ libs/vkd3d/libs/vkd3d-utils/reflection.c | 1116 +++++++++++++++++ .../vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c | 1039 +++++++++++++++ .../libs/vkd3d-utils/vkd3d_utils_private.h | 44 + 7 files changed, 2363 insertions(+), 7 deletions(-) create mode 100644 libs/vkd3d/include/vkd3d_utils.h create mode 100644 libs/vkd3d/libs/vkd3d-utils/reflection.c create mode 100644 libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c create mode 100644 libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h
diff --git a/configure.ac b/configure.ac index 6596f653fb1..45885232c55 100644 --- a/configure.ac +++ b/configure.ac @@ -1134,14 +1134,14 @@ then WINE_NOTICE([libxslt ${notice_platform}MinGW development files not found; using bundled version.]) fi
- WINE_MINGW_PACKAGE_FLAGS(VKD3D,[libvkd3d libvkd3d-shader],[-lvkd3d -lvkd3d-shader], - [WINE_CHECK_MINGW_HEADER(vkd3d.h) + WINE_MINGW_PACKAGE_FLAGS(VKD3D,[libvkd3d-utils libvkd3d libvkd3d-shader],[-lvkd3d-utils -lvkd3d -lvkd3d-shader], + [WINE_CHECK_MINGW_HEADER(vkd3d_utils.h) WINE_CHECK_MINGW_HEADER(vkd3d_shader.h) - if test "$ac_cv_mingw_header_vkd3d_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes" + if test "$ac_cv_mingw_header_vkd3d_utils_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes" then - WINE_CHECK_MINGW_LIB(vkd3d,vkd3d_set_log_callback,[:],[:],[$VKD3D_PE_LIBS]) + WINE_CHECK_MINGW_LIB(vkd3d-utils,vkd3d_utils_set_log_callback,[:],[:],[$VKD3D_PE_LIBS]) WINE_CHECK_MINGW_LIB(vkd3d-shader,vkd3d_shader_build_varying_map,[:],[:],[$VKD3D_PE_LIBS]) - if test "$ac_cv_mingw_lib_vkd3d" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no" + if test "$ac_cv_mingw_lib_vkd3d_utils" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no" then VKD3D_PE_CFLAGS="" VKD3D_PE_LIBS="" diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 3b436919559..91d8dd567ff 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -30,7 +30,7 @@ #include "d3d12.h" #define VK_NO_PROTOTYPES #include "wine/vulkan.h" -#include <vkd3d.h> +#include <vkd3d_utils.h>
WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(vkd3d); @@ -490,7 +490,7 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL) else putenv( "VKD3D_SHADER_DEBUG=none" ); }
- vkd3d_set_log_callback(vkd3d_log_callback); + vkd3d_utils_set_log_callback(vkd3d_log_callback);
return TRUE; } diff --git a/libs/vkd3d/Makefile.in b/libs/vkd3d/Makefile.in index b073790d986..a9d88c54eb6 100644 --- a/libs/vkd3d/Makefile.in +++ b/libs/vkd3d/Makefile.in @@ -31,6 +31,8 @@ SOURCES = \ libs/vkd3d-shader/spirv.c \ libs/vkd3d-shader/tpf.c \ libs/vkd3d-shader/vkd3d_shader_main.c \ + libs/vkd3d-utils/reflection.c \ + libs/vkd3d-utils/vkd3d_utils_main.c \ libs/vkd3d/cache.c \ libs/vkd3d/command.c \ libs/vkd3d/device.c \ diff --git a/libs/vkd3d/include/vkd3d_utils.h b/libs/vkd3d/include/vkd3d_utils.h new file mode 100644 index 00000000000..f5bd79c8e37 --- /dev/null +++ b/libs/vkd3d/include/vkd3d_utils.h @@ -0,0 +1,155 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * + * 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 + */ + +#ifndef __VKD3D_UTILS_H +#define __VKD3D_UTILS_H + +#include <vkd3d.h> +#include <d3dcompiler.h> + +#ifndef VKD3D_UTILS_API_VERSION +#define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * \file vkd3d_utils.h + * + * This file contains definitions for the vkd3d-utils library. + * + * The vkd3d-utils library is a collections of routines to ease the + * porting of a Direct3D 12 application to vkd3d. + * + * \since 1.0 + */ + +#define VKD3D_WAIT_OBJECT_0 (0) +#define VKD3D_WAIT_TIMEOUT (1) +#define VKD3D_WAIT_FAILED (~0u) +#define VKD3D_INFINITE (~0u) + +#ifdef LIBVKD3D_UTILS_SOURCE +# define VKD3D_UTILS_API VKD3D_EXPORT +#else +# define VKD3D_UTILS_API VKD3D_IMPORT +#endif + +/* 1.0 */ +VKD3D_UTILS_API HANDLE vkd3d_create_event(void); +VKD3D_UTILS_API HRESULT vkd3d_signal_event(HANDLE event); +VKD3D_UTILS_API unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds); +VKD3D_UTILS_API void vkd3d_destroy_event(HANDLE event); + +#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L +# define D3D12CreateDevice(...) D3D12CreateDeviceVKD3D(__VA_ARGS__, VKD3D_UTILS_API_VERSION) +#else +# define D3D12CreateDevice(a, b, c, d) D3D12CreateDeviceVKD3D(a, b, c, d, VKD3D_UTILS_API_VERSION) +#endif +VKD3D_UTILS_API HRESULT WINAPI D3D12CreateRootSignatureDeserializer( + const void *data, SIZE_T data_size, REFIID iid, void **deserializer); +VKD3D_UTILS_API HRESULT WINAPI D3D12GetDebugInterface(REFIID iid, void **debug); +VKD3D_UTILS_API HRESULT WINAPI D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *desc, + D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob); + +/* 1.2 */ +VKD3D_UTILS_API HRESULT WINAPI D3D12CreateDeviceVKD3D(IUnknown *adapter, D3D_FEATURE_LEVEL feature_level, + REFIID iid, void **device, enum vkd3d_api_version api_version); +VKD3D_UTILS_API HRESULT WINAPI D3D12CreateVersionedRootSignatureDeserializer(const void *data, + SIZE_T data_size, REFIID iid, void **deserializer); +VKD3D_UTILS_API HRESULT WINAPI D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc, + ID3DBlob **blob, ID3DBlob **error_blob); + +/* 1.3 */ +VKD3D_UTILS_API HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, + const char *target, UINT flags, UINT effect_flags, ID3DBlob **shader, ID3DBlob **error_messages); +/** + * D3DCompile2() targets the behaviour of d3dcompiler_47.dll. To target the + * behaviour of other d3dcompiler versions, use D3DCompile2VKD3D(). + * + * \since 1.3 + */ +VKD3D_UTILS_API HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, + const char *target, UINT flags, UINT effect_flags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, + ID3DBlob **error_messages); +VKD3D_UTILS_API HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob); +VKD3D_UTILS_API HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, + ID3DBlob **shader, ID3DBlob **error_messages); + +/** + * Set a callback to be called when vkd3d-utils outputs debug logging. + * + * If NULL, or if this function has not been called, libvkd3d-utils will print + * all enabled log output to stderr. + * + * Calling this function will also set the log callback for libvkd3d and + * libvkd3d-shader. + * + * \param callback Callback function to set. + * + * \since 1.4 + */ +VKD3D_UTILS_API void vkd3d_utils_set_log_callback(PFN_vkd3d_log callback); + +/** \since 1.10 */ +VKD3D_UTILS_API HRESULT WINAPI D3DGetBlobPart(const void *data, + SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob); +/** \since 1.10 */ +VKD3D_UTILS_API HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob); +/** \since 1.10 */ +VKD3D_UTILS_API HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob); +/** \since 1.10 */ +VKD3D_UTILS_API HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob); +/** \since 1.10 */ +VKD3D_UTILS_API HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob); +/** \since 1.10 */ +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); +/** \since 1.11 */ +VKD3D_UTILS_API HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection); + +/** + * As D3DCompile2(), but with an extra argument that allows targeting + * different d3dcompiler versions. + * + * \param compiler_version The d3dcompiler version to target. This should be + * set to the numerical value in the d3dcompiler library name. E.g. to target + * the behaviour of d3dcompiler_36.dll, set this parameter to 36. + * + * \since 1.14 + */ +VKD3D_UTILS_API HRESULT WINAPI D3DCompile2VKD3D(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, + const char *target, UINT flags, UINT effect_flags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader, + ID3DBlob **error_messages, unsigned int compiler_version); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __VKD3D_UTILS_H */ diff --git a/libs/vkd3d/libs/vkd3d-utils/reflection.c b/libs/vkd3d/libs/vkd3d-utils/reflection.c new file mode 100644 index 00000000000..d6d9ce2a508 --- /dev/null +++ b/libs/vkd3d/libs/vkd3d-utils/reflection.c @@ -0,0 +1,1116 @@ +/* + * Copyright 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 "vkd3d_utils_private.h" +#include <d3dcommon.h> +#include <d3d12shader.h> + +struct d3d12_type +{ + ID3D12ShaderReflectionType ID3D12ShaderReflectionType_iface; + D3D12_SHADER_TYPE_DESC desc; + + struct d3d12_field *fields; +}; + +struct d3d12_field +{ + struct d3d12_type type; +}; + +struct d3d12_variable +{ + ID3D12ShaderReflectionVariable ID3D12ShaderReflectionVariable_iface; + D3D12_SHADER_VARIABLE_DESC desc; + struct d3d12_buffer *buffer; + + struct d3d12_type type; +}; + +struct d3d12_buffer +{ + ID3D12ShaderReflectionConstantBuffer ID3D12ShaderReflectionConstantBuffer_iface; + D3D12_SHADER_BUFFER_DESC desc; + + struct d3d12_variable *variables; +}; + +struct d3d12_reflection +{ + ID3D12ShaderReflection ID3D12ShaderReflection_iface; + unsigned int refcount; + + struct vkd3d_shader_scan_signature_info signature_info; + + D3D12_SHADER_DESC desc; + + struct d3d12_buffer *buffers; + + D3D12_SHADER_INPUT_BIND_DESC *bindings; +}; + +static struct d3d12_buffer null_buffer; +static struct d3d12_variable null_variable; +static struct d3d12_type null_type; + +static struct d3d12_type *impl_from_ID3D12ShaderReflectionType(ID3D12ShaderReflectionType *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_type, ID3D12ShaderReflectionType_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_type_GetDesc( + ID3D12ShaderReflectionType *iface, D3D12_SHADER_TYPE_DESC *desc) +{ + struct d3d12_type *type = impl_from_ID3D12ShaderReflectionType(iface); + + TRACE("iface %p, desc %p.\n", iface, desc); + + if (type == &null_type) + { + WARN("Null type, returning E_FAIL.\n"); + return E_FAIL; + } + + if (!desc) + { + WARN("NULL pointer, returning E_FAIL.\n"); + return E_FAIL; + } + + *desc = type->desc; + return S_OK; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetMemberTypeByIndex( + ID3D12ShaderReflectionType *iface, UINT index) +{ + struct d3d12_type *type = impl_from_ID3D12ShaderReflectionType(iface); + + TRACE("iface %p, index %u.\n", iface, index); + + if (index >= type->desc.Members) + { + WARN("Invalid index %u.\n", index); + return &null_type.ID3D12ShaderReflectionType_iface; + } + + return &type->fields[index].type.ID3D12ShaderReflectionType_iface; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetMemberTypeByName( + ID3D12ShaderReflectionType *iface, const char *name) +{ + FIXME("iface %p, name %s, stub!\n", iface, debugstr_a(name)); + + return NULL; +} + +static const char * STDMETHODCALLTYPE d3d12_type_GetMemberTypeName( + ID3D12ShaderReflectionType *iface, UINT index) +{ + FIXME("iface %p, index %u, stub!\n", iface, index); + + return NULL; +} + +static HRESULT STDMETHODCALLTYPE d3d12_type_IsEqual( + ID3D12ShaderReflectionType *iface, ID3D12ShaderReflectionType *other) +{ + FIXME("iface %p, other %p, stub!\n", iface, other); + return E_NOTIMPL; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetSubType( + ID3D12ShaderReflectionType *iface) +{ + FIXME("iface %p stub!\n", iface); + + return NULL; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetBaseClass( + ID3D12ShaderReflectionType *iface) +{ + FIXME("iface %p stub!\n", iface); + + return NULL; +} + +static UINT STDMETHODCALLTYPE d3d12_type_GetNumInterfaces( + ID3D12ShaderReflectionType *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetInterfaceByIndex( + ID3D12ShaderReflectionType *iface, UINT index) +{ + FIXME("iface %p, index %u stub!\n", iface, index); + + return NULL; +} + +static HRESULT STDMETHODCALLTYPE d3d12_type_IsOfType( + ID3D12ShaderReflectionType *iface, ID3D12ShaderReflectionType *type) +{ + FIXME("iface %p, type %p stub!\n", iface, type); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d3d12_type_ImplementsInterface( + ID3D12ShaderReflectionType *iface, ID3D12ShaderReflectionType *base) +{ + FIXME("iface %p, base %p stub!\n", iface, base); + + return E_NOTIMPL; +} + +static const struct ID3D12ShaderReflectionTypeVtbl d3d12_type_vtbl = +{ + d3d12_type_GetDesc, + d3d12_type_GetMemberTypeByIndex, + d3d12_type_GetMemberTypeByName, + d3d12_type_GetMemberTypeName, + d3d12_type_IsEqual, + d3d12_type_GetSubType, + d3d12_type_GetBaseClass, + d3d12_type_GetNumInterfaces, + d3d12_type_GetInterfaceByIndex, + d3d12_type_IsOfType, + d3d12_type_ImplementsInterface, +}; + +static struct d3d12_type null_type = {{&d3d12_type_vtbl}}; + +static struct d3d12_variable *impl_from_ID3D12ShaderReflectionVariable(ID3D12ShaderReflectionVariable *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_variable, ID3D12ShaderReflectionVariable_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_variable_GetDesc( + ID3D12ShaderReflectionVariable *iface, D3D12_SHADER_VARIABLE_DESC *desc) +{ + struct d3d12_variable *variable = impl_from_ID3D12ShaderReflectionVariable(iface); + + TRACE("iface %p, desc %p.\n", iface, desc); + + if (variable == &null_variable) + { + WARN("Null variable, returning E_FAIL.\n"); + return E_FAIL; + } + + if (!desc) + { + WARN("NULL pointer, returning E_FAIL.\n"); + return E_FAIL; + } + + *desc = variable->desc; + return S_OK; +} + +static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_variable_GetType( + ID3D12ShaderReflectionVariable *iface) +{ + struct d3d12_variable *variable = impl_from_ID3D12ShaderReflectionVariable(iface); + + TRACE("iface %p.\n", iface); + + if (variable == &null_variable) + return &null_type.ID3D12ShaderReflectionType_iface; + + return &variable->type.ID3D12ShaderReflectionType_iface; +} + +static ID3D12ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3d12_variable_GetBuffer( + ID3D12ShaderReflectionVariable *iface) +{ + struct d3d12_variable *variable = impl_from_ID3D12ShaderReflectionVariable(iface); + + TRACE("iface %p.\n", iface); + + return &variable->buffer->ID3D12ShaderReflectionConstantBuffer_iface; +} + +static UINT STDMETHODCALLTYPE d3d12_variable_GetInterfaceSlot( + ID3D12ShaderReflectionVariable *iface, UINT index) +{ + FIXME("iface %p, index %u, stub!\n", iface, index); + + return 0; +} + +static const struct ID3D12ShaderReflectionVariableVtbl d3d12_variable_vtbl = +{ + d3d12_variable_GetDesc, + d3d12_variable_GetType, + d3d12_variable_GetBuffer, + d3d12_variable_GetInterfaceSlot, +}; + +static struct d3d12_variable null_variable = {{&d3d12_variable_vtbl}}; + +static struct d3d12_buffer *impl_from_ID3D12ShaderReflectionConstantBuffer(ID3D12ShaderReflectionConstantBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_buffer, ID3D12ShaderReflectionConstantBuffer_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_buffer_GetDesc( + ID3D12ShaderReflectionConstantBuffer *iface, D3D12_SHADER_BUFFER_DESC *desc) +{ + struct d3d12_buffer *buffer = impl_from_ID3D12ShaderReflectionConstantBuffer(iface); + + TRACE("iface %p, desc %p.\n", iface, desc); + + if (buffer == &null_buffer) + { + WARN("Null constant buffer, returning E_FAIL.\n"); + return E_FAIL; + } + + if (!desc) + { + WARN("NULL pointer, returning E_FAIL.\n"); + return E_FAIL; + } + + *desc = buffer->desc; + return S_OK; +} + +static ID3D12ShaderReflectionVariable * STDMETHODCALLTYPE d3d12_buffer_GetVariableByIndex( + ID3D12ShaderReflectionConstantBuffer *iface, UINT index) +{ + struct d3d12_buffer *buffer = impl_from_ID3D12ShaderReflectionConstantBuffer(iface); + + TRACE("iface %p, index %u.\n", iface, index); + + if (index >= buffer->desc.Variables) + { + WARN("Invalid index %u.\n", index); + return &null_variable.ID3D12ShaderReflectionVariable_iface; + } + + return &buffer->variables[index].ID3D12ShaderReflectionVariable_iface; +} + +static ID3D12ShaderReflectionVariable * STDMETHODCALLTYPE d3d12_buffer_GetVariableByName( + ID3D12ShaderReflectionConstantBuffer *iface, const char *name) +{ + FIXME("iface %p, name %s, stub!\n", iface, debugstr_a(name)); + + return NULL; +} + +static const struct ID3D12ShaderReflectionConstantBufferVtbl d3d12_buffer_vtbl = +{ + d3d12_buffer_GetDesc, + d3d12_buffer_GetVariableByIndex, + d3d12_buffer_GetVariableByName, +}; + +static struct d3d12_buffer null_buffer = {{&d3d12_buffer_vtbl}}; + +static struct d3d12_reflection *impl_from_ID3D12ShaderReflection(ID3D12ShaderReflection *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_reflection, ID3D12ShaderReflection_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_QueryInterface( + ID3D12ShaderReflection *iface, REFIID riid, void **object) +{ + TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object); + + if (IsEqualGUID(riid, &IID_ID3D12ShaderReflection) + || IsEqualGUID(riid, &IID_IUnknown)) + { + ID3D12ShaderReflection_AddRef(iface); + *object = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); + + *object = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d3d12_reflection_AddRef(ID3D12ShaderReflection *iface) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + unsigned int refcount = vkd3d_atomic_increment_u32(&reflection->refcount); + + TRACE("%p increasing refcount to %u.\n", reflection, refcount); + + return refcount; +} + +static void free_type(struct d3d12_type *type) +{ + for (UINT i = 0; i < type->desc.Members; ++i) + free_type(&type->fields[i].type); + vkd3d_free(type->fields); + vkd3d_free((void *)type->desc.Name); +} + +static ULONG STDMETHODCALLTYPE d3d12_reflection_Release(ID3D12ShaderReflection *iface) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + unsigned int refcount = vkd3d_atomic_decrement_u32(&reflection->refcount); + + TRACE("%p decreasing refcount to %u.\n", reflection, refcount); + + if (!refcount) + { + for (UINT i = 0; i < reflection->desc.ConstantBuffers; ++i) + { + struct d3d12_buffer *buffer = &reflection->buffers[i]; + + for (UINT j = 0; j < buffer->desc.Variables; ++j) + { + struct d3d12_variable *variable = &buffer->variables[j]; + + free_type(&variable->type); + vkd3d_free((void *)variable->desc.DefaultValue); + vkd3d_free((void *)variable->desc.Name); + } + vkd3d_free(buffer->variables); + vkd3d_free((void *)buffer->desc.Name); + } + vkd3d_free(reflection->buffers); + + for (UINT i = 0; i < reflection->desc.BoundResources; ++i) + vkd3d_free((void *)reflection->bindings[i].Name); + vkd3d_free(reflection->bindings); + + vkd3d_shader_free_scan_signature_info(&reflection->signature_info); + free(reflection); + } + + return refcount; +} + +/* ID3D12ShaderReflection methods */ + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetDesc(ID3D12ShaderReflection *iface, D3D12_SHADER_DESC *desc) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + + FIXME("iface %p, desc %p partial stub!\n", iface, desc); + + *desc = reflection->desc; + + return S_OK; +} + +static struct ID3D12ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3d12_reflection_GetConstantBufferByIndex( + ID3D12ShaderReflection *iface, UINT index) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + + TRACE("iface %p, index %u.\n", iface, index); + + if (index >= reflection->desc.ConstantBuffers) + { + WARN("Invalid index %u.\n", index); + return &null_buffer.ID3D12ShaderReflectionConstantBuffer_iface; + } + + return &reflection->buffers[index].ID3D12ShaderReflectionConstantBuffer_iface; +} + +static struct ID3D12ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3d12_reflection_GetConstantBufferByName( + ID3D12ShaderReflection *iface, const char *name) +{ + FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name)); + + return NULL; +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetResourceBindingDesc( + ID3D12ShaderReflection *iface, UINT index, D3D12_SHADER_INPUT_BIND_DESC *desc) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + + TRACE("iface %p, index %u, desc %p.\n", iface, index, desc); + + if (index >= reflection->desc.BoundResources) + { + WARN("Invalid index %u.\n", index); + return E_INVALIDARG; + } + + *desc = reflection->bindings[index]; + return S_OK; +} + +static HRESULT get_signature_parameter(const struct vkd3d_shader_signature *signature, + unsigned int index, D3D12_SIGNATURE_PARAMETER_DESC *desc, bool output) +{ + const struct vkd3d_shader_signature_element *e; + + if (!desc || index >= signature->element_count) + { + WARN("Invalid argument specified.\n"); + return E_INVALIDARG; + } + e = &signature->elements[index]; + + desc->SemanticName = e->semantic_name; + desc->SemanticIndex = e->semantic_index; + desc->Register = e->register_index; + desc->SystemValueType = (D3D_NAME)e->sysval_semantic; + desc->ComponentType = (D3D_REGISTER_COMPONENT_TYPE)e->component_type; + desc->Mask = e->mask; + desc->ReadWriteMask = output ? (0xf ^ e->used_mask) : e->used_mask; + desc->Stream = e->stream_index; + desc->MinPrecision = (D3D_MIN_PRECISION)e->min_precision; + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetInputParameterDesc( + ID3D12ShaderReflection *iface, UINT index, D3D12_SIGNATURE_PARAMETER_DESC *desc) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + + TRACE("iface %p, index %u, desc %p.\n", iface, index, desc); + + return get_signature_parameter(&reflection->signature_info.input, index, desc, false); +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetOutputParameterDesc( + ID3D12ShaderReflection *iface, UINT index, D3D12_SIGNATURE_PARAMETER_DESC *desc) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + + TRACE("iface %p, index %u, desc %p.\n", iface, index, desc); + + return get_signature_parameter(&reflection->signature_info.output, index, desc, true); +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetPatchConstantParameterDesc( + ID3D12ShaderReflection *iface, UINT index, D3D12_SIGNATURE_PARAMETER_DESC *desc) +{ + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); + bool output = ((reflection->desc.Version & 0xffff0000) >> 16) == D3D12_SHVER_HULL_SHADER; + + TRACE("iface %p, index %u, desc %p.\n", iface, index, desc); + + return get_signature_parameter(&reflection->signature_info.patch_constant, index, desc, output); +} + +static struct ID3D12ShaderReflectionVariable * STDMETHODCALLTYPE d3d12_reflection_GetVariableByName( + ID3D12ShaderReflection *iface, const char *name) +{ + FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name)); + + return NULL; +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetResourceBindingDescByName( + ID3D12ShaderReflection *iface, const char *name, D3D12_SHADER_INPUT_BIND_DESC *desc) +{ + FIXME("iface %p, name %s, desc %p stub!\n", iface, debugstr_a(name), desc); + + return E_NOTIMPL; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetMovInstructionCount(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetMovcInstructionCount(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetConversionInstructionCount(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetBitwiseInstructionCount(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static D3D_PRIMITIVE STDMETHODCALLTYPE d3d12_reflection_GetGSInputPrimitive(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static BOOL STDMETHODCALLTYPE d3d12_reflection_IsSampleFrequencyShader(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return FALSE; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetNumInterfaceSlots(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetMinFeatureLevel( + ID3D12ShaderReflection *iface, D3D_FEATURE_LEVEL *level) +{ + FIXME("iface %p, level %p stub!\n", iface, level); + + return E_NOTIMPL; +} + +static UINT STDMETHODCALLTYPE d3d12_reflection_GetThreadGroupSize( + ID3D12ShaderReflection *iface, UINT *sizex, UINT *sizey, UINT *sizez) +{ + FIXME("iface %p, sizex %p, sizey %p, sizez %p stub!\n", iface, sizex, sizey, sizez); + + return 0; +} + +static UINT64 STDMETHODCALLTYPE d3d12_reflection_GetRequiresFlags(ID3D12ShaderReflection *iface) +{ + FIXME("iface %p stub!\n", iface); + + return 0; +} + +static const struct ID3D12ShaderReflectionVtbl d3d12_reflection_vtbl = +{ + /* IUnknown methods */ + d3d12_reflection_QueryInterface, + d3d12_reflection_AddRef, + d3d12_reflection_Release, + /* ID3D12ShaderReflection methods */ + d3d12_reflection_GetDesc, + d3d12_reflection_GetConstantBufferByIndex, + d3d12_reflection_GetConstantBufferByName, + d3d12_reflection_GetResourceBindingDesc, + d3d12_reflection_GetInputParameterDesc, + d3d12_reflection_GetOutputParameterDesc, + d3d12_reflection_GetPatchConstantParameterDesc, + d3d12_reflection_GetVariableByName, + d3d12_reflection_GetResourceBindingDescByName, + d3d12_reflection_GetMovInstructionCount, + d3d12_reflection_GetMovcInstructionCount, + d3d12_reflection_GetConversionInstructionCount, + d3d12_reflection_GetBitwiseInstructionCount, + d3d12_reflection_GetGSInputPrimitive, + d3d12_reflection_IsSampleFrequencyShader, + d3d12_reflection_GetNumInterfaceSlots, + d3d12_reflection_GetMinFeatureLevel, + d3d12_reflection_GetThreadGroupSize, + d3d12_reflection_GetRequiresFlags, +}; + +static bool require_space(size_t offset, size_t count, size_t size, size_t data_size) +{ + return !count || (data_size - offset) / count >= size; +} + +/* Return a pointer to data in a code blob, with bounds checking. */ +static const void *get_data_ptr(const struct vkd3d_shader_code *code, + uint32_t offset, uint32_t count, uint32_t size) +{ + if (!require_space(offset, count, size, code->size)) + { + WARN("Offset %#x and size %#x exceeds section size %#zx.\n", offset, size, code->size); + return NULL; + } + + return (const uint8_t *)code->code + offset; +} + +static HRESULT get_string(const struct vkd3d_shader_code *code, uint32_t offset, char **ret) +{ + const char *str; + char *end; + + if (offset >= code->size) + { + WARN("Offset %#x exceeds size %#zx.\n", offset, code->size); + return E_INVALIDARG; + } + + str = (const char *)code->code + offset; + if (!(end = memchr(str, 0, code->size - offset))) + { + WARN("String at %#x is not properly zero-terminated.\n", offset); + return E_INVALIDARG; + } + + if (!(*ret = vkd3d_memdup(str, end + 1 - str))) + return E_OUTOFMEMORY; + return S_OK; +} + +struct rdef_header +{ + uint32_t buffer_count; + uint32_t buffers_offset; + uint32_t binding_count; + uint32_t bindings_offset; + uint8_t minor_version; + uint8_t major_version; + uint16_t type; + uint32_t compile_flags; + uint32_t creator_offset; +}; + +struct rdef_rd11 +{ + uint32_t magic; + uint32_t header_size; + uint32_t buffer_size; + uint32_t binding_size; + uint32_t variable_size; + uint32_t type_size; + uint32_t field_size; + /* Always zero. Possibly either padding or a null terminator? */ + uint32_t zero; +}; + +struct rdef_buffer +{ + uint32_t name_offset; + uint32_t var_count; + uint32_t vars_offset; + uint32_t size; + uint32_t flags; + uint32_t type; +}; + +struct rdef_variable +{ + uint32_t name_offset; + uint32_t offset; + uint32_t size; + uint32_t flags; + uint32_t type_offset; + uint32_t default_value_offset; + uint32_t resource_binding; + uint32_t resource_count; + uint32_t sampler_binding; + uint32_t sampler_count; +}; + +struct rdef_type +{ + uint16_t class; + uint16_t base_type; + uint16_t row_count; + uint16_t column_count; + uint16_t element_count; + uint16_t field_count; + uint32_t fields_offset; + /* Probably related to interfaces. */ + uint32_t unknown[4]; + uint32_t name_offset; +}; + +struct rdef_field +{ + uint32_t name_offset; + uint32_t type_offset; + uint32_t offset; +}; + +struct rdef_binding +{ + uint32_t name_offset; + uint32_t type; + uint32_t resource_format; + uint32_t dimension; + uint32_t multisample_count; + uint32_t index; + uint32_t count; + uint32_t flags; + uint32_t space; + uint32_t id; +}; + +static HRESULT d3d12_type_init(struct d3d12_type *type, uint32_t type_offset, uint32_t type_size, + const struct vkd3d_shader_code *section, uint32_t field_offset) +{ + struct rdef_type normalized_type = {0}; + const struct rdef_type *rdef_type; + char *name = NULL; + HRESULT hr; + + if (!(rdef_type = get_data_ptr(section, type_offset, 1, type_size))) + return E_INVALIDARG; + memcpy(&normalized_type, rdef_type, type_size); + + if (normalized_type.name_offset && FAILED(hr = get_string(section, normalized_type.name_offset, &name))) + return hr; + + type->ID3D12ShaderReflectionType_iface.lpVtbl = &d3d12_type_vtbl; + + type->desc.Class = normalized_type.class; + type->desc.Type = normalized_type.base_type; + type->desc.Rows = normalized_type.row_count; + type->desc.Columns = normalized_type.column_count; + type->desc.Elements = normalized_type.element_count; + type->desc.Members = normalized_type.field_count; + type->desc.Offset = field_offset; + type->desc.Name = name; + + if (normalized_type.field_count) + { + const struct rdef_field *rdef_fields; + + if (!(rdef_fields = get_data_ptr(section, normalized_type.fields_offset, + normalized_type.field_count, sizeof(*rdef_fields)))) + return E_INVALIDARG; + + if (!(type->fields = vkd3d_calloc(normalized_type.field_count, sizeof(*type->fields)))) + return false; + + for (uint32_t i = 0; i < normalized_type.field_count; ++i) + { + const struct rdef_field *rdef_field = &rdef_fields[i]; + + if ((hr = d3d12_type_init(&type->fields[i].type, rdef_field->type_offset, + type_size, section, rdef_field->offset))) + return hr; + } + } + + return S_OK; +} + +static HRESULT d3d12_variable_init(struct d3d12_variable *variable, const struct rdef_variable *rdef_variable, + const struct vkd3d_shader_code *section, uint32_t type_size) +{ + HRESULT hr; + char *name; + + if (FAILED(hr = get_string(section, rdef_variable->name_offset, &name))) + return hr; + + variable->ID3D12ShaderReflectionVariable_iface.lpVtbl = &d3d12_variable_vtbl; + + variable->desc.Name = name; + variable->desc.StartOffset = rdef_variable->offset; + variable->desc.Size = rdef_variable->size; + variable->desc.uFlags = rdef_variable->flags; + variable->desc.StartTexture = rdef_variable->resource_binding; + variable->desc.TextureSize = rdef_variable->resource_count; + variable->desc.StartSampler = rdef_variable->sampler_binding; + variable->desc.SamplerSize = rdef_variable->sampler_count; + + if (rdef_variable->default_value_offset) + { + const void *default_value; + + if (!(default_value = get_data_ptr(section, rdef_variable->default_value_offset, 1, rdef_variable->size))) + return E_INVALIDARG; + + if (!(variable->desc.DefaultValue = vkd3d_memdup(default_value, rdef_variable->size))) + return E_OUTOFMEMORY; + } + + return d3d12_type_init(&variable->type, rdef_variable->type_offset, type_size, section, 0); +} + +static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_buffer *rdef_buffer, + const struct vkd3d_shader_code *section, uint32_t variable_size, uint32_t type_size) +{ + HRESULT hr; + char *name; + + if ((FAILED(hr = get_string(section, rdef_buffer->name_offset, &name)))) + return hr; + + buffer->ID3D12ShaderReflectionConstantBuffer_iface.lpVtbl = &d3d12_buffer_vtbl; + + buffer->desc.Type = rdef_buffer->type; + buffer->desc.Variables = rdef_buffer->var_count; + buffer->desc.Size = rdef_buffer->size; + buffer->desc.uFlags = rdef_buffer->flags; + buffer->desc.Name = name; + + if (!(buffer->variables = vkd3d_calloc(rdef_buffer->var_count, sizeof(*buffer->variables)))) + return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < rdef_buffer->var_count; ++i) + { + struct rdef_variable normalized_variable = {0}; + const struct rdef_variable *rdef_variable; + + if (!(rdef_variable = get_data_ptr(section, rdef_buffer->vars_offset + (i * variable_size), 1, variable_size))) + return E_INVALIDARG; + + normalized_variable.resource_binding = ~0u; + normalized_variable.sampler_binding = ~0u; + memcpy(&normalized_variable, rdef_variable, variable_size); + + if ((hr = d3d12_variable_init(&buffer->variables[i], &normalized_variable, section, type_size))) + return hr; + } + + return S_OK; +} + +static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3d_shader_code *section) +{ + uint32_t variable_size = offsetof(struct rdef_variable, resource_binding); + uint32_t binding_size = offsetof(struct rdef_binding, space); + uint32_t type_size = offsetof(struct rdef_type, unknown); + const struct rdef_header *header; + const struct rdef_rd11 *rd11; + HRESULT hr; + + if (!(header = get_data_ptr(section, 0, 1, sizeof(*header)))) + return E_INVALIDARG; + + if (header->major_version >= 5) + { + if (!(rd11 = get_data_ptr(section, sizeof(*header), 1, sizeof(*rd11)))) + return E_INVALIDARG; + + /* RD11 is emitted for 5.0, the reversed version for 5.1 and 6.0. + * This corresponds to a difference in the binding_size member, but + * it's not clear why the magic also changed there. */ + if (rd11->magic != TAG_RD11 && rd11->magic != TAG_RD11_REVERSE) + { + FIXME("Unknown tag %#x.\n", rd11->magic); + return E_INVALIDARG; + } + + if (rd11->header_size != sizeof(struct rdef_header) + sizeof(struct rdef_rd11)) + { + FIXME("Unexpected header size %#x.\n", rd11->header_size); + return E_INVALIDARG; + } + + if (rd11->buffer_size != sizeof(struct rdef_buffer)) + { + FIXME("Unexpected buffer size %#x.\n", rd11->buffer_size); + return E_INVALIDARG; + } + + if (rd11->variable_size != sizeof(struct rdef_variable)) + { + FIXME("Unexpected variable size %#x.\n", rd11->variable_size); + return E_INVALIDARG; + } + variable_size = rd11->variable_size; + + if (rd11->binding_size != sizeof(struct rdef_binding) + && rd11->binding_size != offsetof(struct rdef_binding, space)) + { + FIXME("Unexpected binding size %#x.\n", rd11->binding_size); + return E_INVALIDARG; + } + binding_size = rd11->binding_size; + + if (rd11->type_size != sizeof(struct rdef_type)) + { + FIXME("Unexpected type size %#x.\n", rd11->type_size); + return E_INVALIDARG; + } + type_size = rd11->type_size; + + if (rd11->zero) + { + FIXME("Unexpected field %#x.\n", rd11->zero); + return E_INVALIDARG; + } + } + + reflection->desc.ConstantBuffers = header->buffer_count; + + if (header->buffer_count) + { + const struct rdef_buffer *rdef_buffers; + + if (!(rdef_buffers = get_data_ptr(section, header->buffers_offset, + header->buffer_count, sizeof(*rdef_buffers)))) + return E_INVALIDARG; + + if (!(reflection->buffers = vkd3d_calloc(header->buffer_count, sizeof(*reflection->buffers)))) + return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < header->buffer_count; ++i) + { + if ((hr = d3d12_buffer_init(&reflection->buffers[i], &rdef_buffers[i], section, variable_size, type_size))) + return hr; + } + } + + reflection->desc.BoundResources = header->binding_count; + + if (header->binding_count) + { + if (!(reflection->bindings = vkd3d_calloc(header->binding_count, sizeof(*reflection->bindings)))) + return E_OUTOFMEMORY; + + for (uint32_t i = 0; i < header->binding_count; ++i) + { + const struct rdef_binding *rdef_binding; + D3D12_SHADER_INPUT_BIND_DESC *binding; + char *name; + + if (!(rdef_binding = get_data_ptr(section, header->bindings_offset + (i * binding_size), 1, binding_size))) + return E_INVALIDARG; + + if (FAILED(hr = get_string(section, rdef_binding->name_offset, &name))) + return hr; + + binding = &reflection->bindings[i]; + + binding->Name = name; + binding->Type = rdef_binding->type; + binding->BindPoint = rdef_binding->index; + binding->BindCount = rdef_binding->count; + binding->uFlags = rdef_binding->flags; + binding->ReturnType = rdef_binding->resource_format; + binding->Dimension = rdef_binding->dimension; + binding->NumSamples = rdef_binding->multisample_count; + if (binding_size == sizeof(*rdef_binding)) + { + binding->Space = rdef_binding->space; + binding->uID = rdef_binding->id; + } + else + { + binding->Space = 0; + binding->uID = rdef_binding->index; + } + } + } + + return S_OK; +} + +static HRESULT d3d12_reflection_init(struct d3d12_reflection *reflection, const void *data, size_t data_size) +{ + struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; + struct vkd3d_shader_dxbc_desc dxbc_desc; + bool found_rdef = false; + enum vkd3d_result ret; + HRESULT hr; + + reflection->ID3D12ShaderReflection_iface.lpVtbl = &d3d12_reflection_vtbl; + reflection->refcount = 1; + + compile_info.source.code = data; + compile_info.source.size = data_size; + compile_info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF; + + compile_info.next = &reflection->signature_info; + reflection->signature_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO; + + if (FAILED(hr = hresult_from_vkd3d_result(vkd3d_shader_scan(&compile_info, NULL)))) + return hr; + + if ((ret = vkd3d_shader_parse_dxbc(&compile_info.source, 0, &dxbc_desc, NULL))) + { + vkd3d_shader_free_scan_signature_info(&reflection->signature_info); + return hresult_from_vkd3d_result(ret); + } + + for (unsigned int i = 0; i < dxbc_desc.section_count; ++i) + { + const struct vkd3d_shader_dxbc_section_desc *section = &dxbc_desc.sections[i]; + + if (section->tag == TAG_RDEF) + { + if (found_rdef) + { + FIXME("Multiple RDEF chunks.\n"); + continue; + } + + if (FAILED(hr = parse_rdef(reflection, §ion->data))) + goto fail; + found_rdef = true; + } + else if (section->tag == TAG_SHDR || section->tag == TAG_SHEX) + { + const uint32_t *version; + + if (!(version = get_data_ptr(§ion->data, 0, 1, sizeof(*version)))) + { + hr = E_INVALIDARG; + goto fail; + } + reflection->desc.Version = *version; + } + } + + reflection->desc.InputParameters = reflection->signature_info.input.element_count; + reflection->desc.OutputParameters = reflection->signature_info.output.element_count; + reflection->desc.PatchConstantParameters = reflection->signature_info.patch_constant.element_count; + + vkd3d_shader_free_dxbc(&dxbc_desc); + + return S_OK; + +fail: + vkd3d_shader_free_scan_signature_info(&reflection->signature_info); + vkd3d_shader_free_dxbc(&dxbc_desc); + return hr; +} + +HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection) +{ + struct d3d12_reflection *object; + HRESULT hr; + + TRACE("data %p, data_size %"PRIuPTR", iid %s, reflection %p.\n", + data, (uintptr_t)data_size, debugstr_guid(iid), reflection); + + if (!IsEqualGUID(iid, &IID_ID3D12ShaderReflection)) + { + WARN("Invalid iid %s.\n", debugstr_guid(iid)); + return E_INVALIDARG; + } + + if (!(object = vkd3d_calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d3d12_reflection_init(object, data, data_size))) + { + free(object); + return hr; + } + + *reflection = &object->ID3D12ShaderReflection_iface; + TRACE("Created reflection %p.\n", object); + return S_OK; +} diff --git a/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c new file mode 100644 index 00000000000..88374e4c74d --- /dev/null +++ b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c @@ -0,0 +1,1039 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * + * 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 "vkd3d_utils_private.h" +#undef D3D12CreateDevice + +static const char *debug_d3d_blob_part(D3D_BLOB_PART part) +{ + switch (part) + { +#define TO_STR(x) case x: return #x + TO_STR(D3D_BLOB_INPUT_SIGNATURE_BLOB); + TO_STR(D3D_BLOB_OUTPUT_SIGNATURE_BLOB); + TO_STR(D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB); + TO_STR(D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB); + TO_STR(D3D_BLOB_ALL_SIGNATURE_BLOB); + TO_STR(D3D_BLOB_DEBUG_INFO); + TO_STR(D3D_BLOB_LEGACY_SHADER); + TO_STR(D3D_BLOB_XNA_PREPASS_SHADER); + TO_STR(D3D_BLOB_XNA_SHADER); + TO_STR(D3D_BLOB_PDB); + TO_STR(D3D_BLOB_PRIVATE_DATA); + TO_STR(D3D_BLOB_ROOT_SIGNATURE); + TO_STR(D3D_BLOB_DEBUG_NAME); + + TO_STR(D3D_BLOB_TEST_ALTERNATE_SHADER); + TO_STR(D3D_BLOB_TEST_COMPILE_DETAILS); + TO_STR(D3D_BLOB_TEST_COMPILE_PERF); + TO_STR(D3D_BLOB_TEST_COMPILE_REPORT); +#undef TO_STR + default: + return vkd3d_dbg_sprintf("<D3D_BLOB_PART %#x>", part); + } +} + +HRESULT WINAPI D3D12GetDebugInterface(REFIID iid, void **debug) +{ + FIXME("iid %s, debug %p stub!\n", debugstr_guid(iid), debug); + + return E_NOTIMPL; +} + +HRESULT WINAPI D3D12CreateDeviceVKD3D(IUnknown *adapter, D3D_FEATURE_LEVEL minimum_feature_level, + REFIID iid, void **device, enum vkd3d_api_version api_version) +{ + struct vkd3d_optional_instance_extensions_info optional_instance_extensions_info; + struct vkd3d_optional_device_extensions_info optional_device_extensions_info; + struct vkd3d_instance_create_info instance_create_info; + struct vkd3d_device_create_info device_create_info; + + static const char * const optional_instance_extensions[] = + { + VK_KHR_SURFACE_EXTENSION_NAME, + "VK_KHR_android_surface", + "VK_KHR_wayland_surface", + "VK_KHR_win32_surface", + "VK_KHR_xcb_surface", + "VK_KHR_xlib_surface", + "VK_EXT_metal_surface", + "VK_MVK_macos_surface", + "VK_MVK_ios_surface", + }; + static const char * const optional_device_extensions[] = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + struct vkd3d_application_info application_info = + { + .type = VKD3D_STRUCTURE_TYPE_APPLICATION_INFO, + .api_version = api_version, + }; + + TRACE("adapter %p, minimum_feature_level %#x, iid %s, device %p, api_version %#x.\n", + adapter, minimum_feature_level, debugstr_guid(iid), device, api_version); + + if (adapter) + FIXME("Ignoring adapter %p.\n", adapter); + + memset(&optional_instance_extensions_info, 0, sizeof(optional_instance_extensions_info)); + optional_instance_extensions_info.type = VKD3D_STRUCTURE_TYPE_OPTIONAL_INSTANCE_EXTENSIONS_INFO; + optional_instance_extensions_info.next = &application_info; + optional_instance_extensions_info.extensions = optional_instance_extensions; + optional_instance_extensions_info.extension_count = ARRAY_SIZE(optional_instance_extensions); + + memset(&instance_create_info, 0, sizeof(instance_create_info)); + instance_create_info.type = VKD3D_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_create_info.next = &optional_instance_extensions_info; + instance_create_info.pfn_signal_event = vkd3d_signal_event; + instance_create_info.wchar_size = sizeof(WCHAR); + + memset(&optional_device_extensions_info, 0, sizeof(optional_device_extensions_info)); + optional_device_extensions_info.type = VKD3D_STRUCTURE_TYPE_OPTIONAL_DEVICE_EXTENSIONS_INFO; + optional_device_extensions_info.extensions = optional_device_extensions; + optional_device_extensions_info.extension_count = ARRAY_SIZE(optional_device_extensions); + + memset(&device_create_info, 0, sizeof(device_create_info)); + device_create_info.type = VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.next = &optional_device_extensions_info; + device_create_info.minimum_feature_level = minimum_feature_level; + device_create_info.instance_create_info = &instance_create_info; + + return vkd3d_create_device(&device_create_info, iid, device); +} + +VKD3D_UTILS_API HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, + D3D_FEATURE_LEVEL minimum_feature_level, REFIID iid, void **device) +{ + return D3D12CreateDeviceVKD3D(adapter, minimum_feature_level, iid, device, VKD3D_API_VERSION_1_0); +} + +HRESULT WINAPI D3D12CreateRootSignatureDeserializer(const void *data, SIZE_T data_size, + REFIID iid, void **deserializer) +{ + TRACE("data %p, data_size %"PRIuPTR", iid %s, deserializer %p.\n", + data, (uintptr_t)data_size, debugstr_guid(iid), deserializer); + + return vkd3d_create_root_signature_deserializer(data, data_size, iid, deserializer); +} + +HRESULT WINAPI D3D12CreateVersionedRootSignatureDeserializer(const void *data, SIZE_T data_size, + REFIID iid,void **deserializer) +{ + TRACE("data %p, data_size %"PRIuPTR", iid %s, deserializer %p.\n", + data, (uintptr_t)data_size, debugstr_guid(iid), deserializer); + + return vkd3d_create_versioned_root_signature_deserializer(data, data_size, iid, deserializer); +} + +HRESULT WINAPI D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *desc, + D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob) +{ + TRACE("desc %p, version %#x, blob %p, error_blob %p.\n", desc, version, blob, error_blob); + + return vkd3d_serialize_root_signature(desc, version, blob, error_blob); +} + +HRESULT WINAPI D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc, + ID3DBlob **blob, ID3DBlob **error_blob) +{ + TRACE("desc %p, blob %p, error_blob %p.\n", desc, blob, error_blob); + + return vkd3d_serialize_versioned_root_signature(desc, blob, error_blob); +} + +static int open_include(const char *filename, bool local, const char *parent_data, void *context, + struct vkd3d_shader_code *code) +{ + ID3DInclude *iface = context; + unsigned int size = 0; + + if (!iface) + return VKD3D_ERROR; + + memset(code, 0, sizeof(*code)); + if (FAILED(ID3DInclude_Open(iface, local ? D3D_INCLUDE_LOCAL : D3D_INCLUDE_SYSTEM, + filename, parent_data, &code->code, &size))) + return VKD3D_ERROR; + + code->size = size; + return VKD3D_OK; +} + +static void close_include(const struct vkd3d_shader_code *code, void *context) +{ + ID3DInclude *iface = context; + + ID3DInclude_Close(iface, code->code); +} + +static enum vkd3d_shader_target_type get_target_for_profile(const char *profile) +{ + size_t profile_len, i; + + static const char * const d3dbc_profiles[] = + { + "ps.1.", + "ps.2.", + "ps.3.", + + "ps_1_", + "ps_2_", + "ps_3_", + + "vs.1.", + "vs.2.", + "vs.3.", + + "vs_1_", + "vs_2_", + "vs_3_", + + "tx_1_", + }; + + static const char * const fx_profiles[] = + { + "fx_2_0", + "fx_4_0", + "fx_4_1", + "fx_5_0", + }; + + profile_len = strlen(profile); + for (i = 0; i < ARRAY_SIZE(d3dbc_profiles); ++i) + { + size_t len = strlen(d3dbc_profiles[i]); + + if (len <= profile_len && !memcmp(profile, d3dbc_profiles[i], len)) + return VKD3D_SHADER_TARGET_D3D_BYTECODE; + } + + for (i = 0; i < ARRAY_SIZE(fx_profiles); ++i) + { + if (!strcmp(profile, fx_profiles[i])) + return VKD3D_SHADER_TARGET_FX; + } + + return VKD3D_SHADER_TARGET_DXBC_TPF; +} + +HRESULT WINAPI D3DCompile2VKD3D(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entry_point, + const char *profile, UINT flags, UINT effect_flags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader_blob, + ID3DBlob **messages_blob, unsigned int compiler_version) +{ + struct vkd3d_shader_preprocess_info preprocess_info; + struct vkd3d_shader_hlsl_source_info hlsl_info; + struct vkd3d_shader_compile_option options[7]; + struct vkd3d_shader_compile_info compile_info; + struct vkd3d_shader_compile_option *option; + struct vkd3d_shader_code byte_code; + const D3D_SHADER_MACRO *macro; + char *messages; + HRESULT hr; + int ret; + + TRACE("data %p, data_size %"PRIuPTR", filename %s, macros %p, include %p, entry_point %s, " + "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, " + "secondary_data_size %"PRIuPTR", shader_blob %p, messages_blob %p, compiler_version %u.\n", + data, (uintptr_t)data_size, debugstr_a(filename), macros, include, debugstr_a(entry_point), + debugstr_a(profile), flags, effect_flags, secondary_flags, secondary_data, + (uintptr_t)secondary_data_size, shader_blob, messages_blob, compiler_version); + + if (flags & ~(D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR)) + FIXME("Ignoring flags %#x.\n", flags); + if (effect_flags & ~D3DCOMPILE_EFFECT_CHILD_EFFECT) + FIXME("Ignoring effect flags %#x.\n", effect_flags); + if (secondary_flags) + FIXME("Ignoring secondary flags %#x.\n", secondary_flags); + + if (messages_blob) + *messages_blob = NULL; + + option = &options[0]; + option->name = VKD3D_SHADER_COMPILE_OPTION_API_VERSION; + option->value = VKD3D_SHADER_API_VERSION_1_14; + + compile_info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; + compile_info.next = &preprocess_info; + compile_info.source.code = data; + compile_info.source.size = data_size; + compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL; + compile_info.target_type = get_target_for_profile(profile); + compile_info.options = options; + compile_info.option_count = 1; + compile_info.log_level = VKD3D_SHADER_LOG_INFO; + compile_info.source_name = filename; + + preprocess_info.type = VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO; + preprocess_info.next = &hlsl_info; + preprocess_info.macros = (const struct vkd3d_shader_macro *)macros; + preprocess_info.macro_count = 0; + if (macros) + { + for (macro = macros; macro->Name; ++macro) + ++preprocess_info.macro_count; + } + preprocess_info.pfn_open_include = open_include; + preprocess_info.pfn_close_include = close_include; + preprocess_info.include_context = include; + + hlsl_info.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO; + hlsl_info.next = NULL; + hlsl_info.profile = profile; + hlsl_info.entry_point = entry_point; + hlsl_info.secondary_code.code = secondary_data; + hlsl_info.secondary_code.size = secondary_data_size; + + if (!(flags & D3DCOMPILE_DEBUG)) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG; + option->value = true; + } + + if (flags & (D3DCOMPILE_PACK_MATRIX_ROW_MAJOR | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR)) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ORDER; + option->value = 0; + if (flags & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR) + option->value |= VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ROW_MAJOR; + if (flags & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR) + option->value |= VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_COLUMN_MAJOR; + } + + if (flags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_BACKWARD_COMPATIBILITY; + option->value = VKD3D_SHADER_COMPILE_OPTION_BACKCOMPAT_MAP_SEMANTIC_NAMES; + } + + if (effect_flags & D3DCOMPILE_EFFECT_CHILD_EFFECT) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_CHILD_EFFECT; + option->value = true; + } + + if (compiler_version <= 39) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_INCLUDE_EMPTY_BUFFERS_IN_EFFECTS; + option->value = true; + } + + if (compiler_version < 42) + { + option = &options[compile_info.option_count++]; + option->name = VKD3D_SHADER_COMPILE_OPTION_WARN_IMPLICIT_TRUNCATION; + option->value = false; + } + + ret = vkd3d_shader_compile(&compile_info, &byte_code, &messages); + + if (messages && messages_blob) + { + if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), messages_blob))) + { + vkd3d_shader_free_messages(messages); + vkd3d_shader_free_shader_code(&byte_code); + return hr; + } + messages = NULL; + } + vkd3d_shader_free_messages(messages); + + if (!ret) + { + /* Unlike other effect profiles fx_4_x is using DXBC container. */ + if (!strcmp(profile, "fx_4_0") || !strcmp(profile, "fx_4_1")) + { + struct vkd3d_shader_dxbc_section_desc section = { .tag = TAG_FX10, .data = byte_code }; + struct vkd3d_shader_code dxbc; + + ret = vkd3d_shader_serialize_dxbc(1, §ion, &dxbc, NULL); + vkd3d_shader_free_shader_code(&byte_code); + if (ret) + return hresult_from_vkd3d_result(ret); + + byte_code = dxbc; + } + + if (FAILED(hr = vkd3d_blob_create((void *)byte_code.code, byte_code.size, shader_blob))) + { + vkd3d_shader_free_shader_code(&byte_code); + return hr; + } + } + + return hresult_from_vkd3d_result(ret); +} + +HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entry_point, + const char *profile, UINT flags, UINT effect_flags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader_blob, + ID3DBlob **messages_blob) +{ + TRACE("data %p, data_size %"PRIuPTR", filename %s, macros %p, include %p, entry_point %s, " + "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, " + "secondary_data_size %"PRIuPTR", shader_blob %p, messages_blob %p.\n", + data, (uintptr_t)data_size, debugstr_a(filename), macros, include, debugstr_a(entry_point), + debugstr_a(profile), flags, effect_flags, secondary_flags, secondary_data, + (uintptr_t)secondary_data_size, shader_blob, messages_blob); + + return D3DCompile2VKD3D(data, data_size, filename, macros, include, + entry_point, profile, flags, effect_flags, secondary_flags, + secondary_data, secondary_data_size, shader_blob, messages_blob, 47); +} + +HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entrypoint, + const char *profile, UINT flags, UINT effect_flags, ID3DBlob **shader, ID3DBlob **error_messages) +{ + TRACE("data %p, data_size %"PRIuPTR", filename %s, macros %p, include %p, entrypoint %s, " + "profile %s, flags %#x, effect_flags %#x, shader %p, error_messages %p.\n", + data, (uintptr_t)data_size, debugstr_a(filename), macros, include, debugstr_a(entrypoint), + debugstr_a(profile), flags, effect_flags, shader, error_messages); + + return D3DCompile2(data, data_size, filename, macros, include, entrypoint, profile, flags, + effect_flags, 0, NULL, 0, shader, error_messages); +} + +HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename, + const D3D_SHADER_MACRO *macros, ID3DInclude *include, + ID3DBlob **preprocessed_blob, ID3DBlob **messages_blob) +{ + struct vkd3d_shader_preprocess_info preprocess_info; + struct vkd3d_shader_compile_info compile_info; + struct vkd3d_shader_code preprocessed_code; + const D3D_SHADER_MACRO *macro; + 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_14}, + }; + + TRACE("data %p, size %"PRIuPTR", filename %s, macros %p, include %p, preprocessed_blob %p, messages_blob %p.\n", + data, (uintptr_t)size, debugstr_a(filename), macros, include, preprocessed_blob, messages_blob); + + if (messages_blob) + *messages_blob = NULL; + + compile_info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; + compile_info.next = &preprocess_info; + compile_info.source.code = data; + compile_info.source.size = size; + compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL; + compile_info.target_type = VKD3D_SHADER_TARGET_NONE; + compile_info.options = options; + compile_info.option_count = ARRAY_SIZE(options); + compile_info.log_level = VKD3D_SHADER_LOG_INFO; + compile_info.source_name = filename; + + preprocess_info.type = VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO; + preprocess_info.next = NULL; + preprocess_info.macros = (const struct vkd3d_shader_macro *)macros; + preprocess_info.macro_count = 0; + if (macros) + { + for (macro = macros; macro->Name; ++macro) + ++preprocess_info.macro_count; + } + preprocess_info.pfn_open_include = open_include; + preprocess_info.pfn_close_include = close_include; + preprocess_info.include_context = include; + + ret = vkd3d_shader_preprocess(&compile_info, &preprocessed_code, &messages); + + if (messages && messages_blob) + { + if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), messages_blob))) + { + vkd3d_shader_free_messages(messages); + vkd3d_shader_free_shader_code(&preprocessed_code); + return hr; + } + messages = NULL; + } + vkd3d_shader_free_messages(messages); + + if (!ret) + { + if (FAILED(hr = vkd3d_blob_create((void *)preprocessed_code.code, preprocessed_code.size, preprocessed_blob))) + { + vkd3d_shader_free_shader_code(&preprocessed_code); + return hr; + } + } + + return hresult_from_vkd3d_result(ret); +} + +/* Events */ + +#ifdef _WIN32 + +HANDLE vkd3d_create_event(void) +{ + return CreateEventA(NULL, FALSE, FALSE, NULL); +} + +HRESULT vkd3d_signal_event(HANDLE event) +{ + SetEvent(event); + return S_OK; +} + +unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds) +{ + return WaitForSingleObject(event, milliseconds); +} + +void vkd3d_destroy_event(HANDLE event) +{ + CloseHandle(event); +} + +#else /* _WIN32 */ + +#include <pthread.h> + +struct vkd3d_event +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + BOOL is_signaled; +}; + +HANDLE vkd3d_create_event(void) +{ + struct vkd3d_event *event; + int rc; + + TRACE(".\n"); + + if (!(event = vkd3d_malloc(sizeof(*event)))) + return NULL; + + if ((rc = pthread_mutex_init(&event->mutex, NULL))) + { + ERR("Failed to initialize mutex, error %d.\n", rc); + vkd3d_free(event); + return NULL; + } + if ((rc = pthread_cond_init(&event->cond, NULL))) + { + ERR("Failed to initialize condition variable, error %d.\n", rc); + pthread_mutex_destroy(&event->mutex); + vkd3d_free(event); + return NULL; + } + + event->is_signaled = false; + + TRACE("Created event %p.\n", event); + + return event; +} + +unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds) +{ + struct vkd3d_event *impl = event; + int rc; + + TRACE("event %p, milliseconds %u.\n", event, milliseconds); + + if ((rc = pthread_mutex_lock(&impl->mutex))) + { + ERR("Failed to lock mutex, error %d.\n", rc); + return VKD3D_WAIT_FAILED; + } + + if (impl->is_signaled || !milliseconds) + { + bool is_signaled = impl->is_signaled; + impl->is_signaled = false; + pthread_mutex_unlock(&impl->mutex); + return is_signaled ? VKD3D_WAIT_OBJECT_0 : VKD3D_WAIT_TIMEOUT; + } + + if (milliseconds == VKD3D_INFINITE) + { + do + { + if ((rc = pthread_cond_wait(&impl->cond, &impl->mutex))) + { + ERR("Failed to wait on condition variable, error %d.\n", rc); + pthread_mutex_unlock(&impl->mutex); + return VKD3D_WAIT_FAILED; + } + } while (!impl->is_signaled); + + impl->is_signaled = false; + pthread_mutex_unlock(&impl->mutex); + return VKD3D_WAIT_OBJECT_0; + } + + pthread_mutex_unlock(&impl->mutex); + FIXME("Timed wait not implemented yet.\n"); + return VKD3D_WAIT_FAILED; +} + +HRESULT vkd3d_signal_event(HANDLE event) +{ + struct vkd3d_event *impl = event; + int rc; + + TRACE("event %p.\n", event); + + if ((rc = pthread_mutex_lock(&impl->mutex))) + { + ERR("Failed to lock mutex, error %d.\n", rc); + return E_FAIL; + } + impl->is_signaled = true; + pthread_cond_signal(&impl->cond); + pthread_mutex_unlock(&impl->mutex); + + return S_OK; +} + +void vkd3d_destroy_event(HANDLE event) +{ + struct vkd3d_event *impl = event; + int rc; + + TRACE("event %p.\n", event); + + if ((rc = pthread_mutex_destroy(&impl->mutex))) + ERR("Failed to destroy mutex, error %d.\n", rc); + if ((rc = pthread_cond_destroy(&impl->cond))) + ERR("Failed to destroy condition variable, error %d.\n", rc); + vkd3d_free(impl); +} + +#endif /* _WIN32 */ + +HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob) +{ + HRESULT hr; + void *data; + + TRACE("data_size %"PRIuPTR", blob %p.\n", (uintptr_t)data_size, blob); + + if (!blob) + { + WARN("Invalid 'blob' pointer specified.\n"); + return D3DERR_INVALIDCALL; + } + + if (!(data = vkd3d_calloc(data_size, 1))) + return E_OUTOFMEMORY; + + if (FAILED(hr = vkd3d_blob_create(data, data_size, blob))) + { + WARN("Failed to create blob object, hr %s.\n", debugstr_hresult(hr)); + vkd3d_free(data); + } + return hr; +} + +static bool check_blob_part(uint32_t tag, D3D_BLOB_PART part) +{ + bool add = false; + + switch (part) + { + case D3D_BLOB_INPUT_SIGNATURE_BLOB: + if (tag == TAG_ISGN) + add = true; + break; + + case D3D_BLOB_OUTPUT_SIGNATURE_BLOB: + if (tag == TAG_OSGN || tag == TAG_OSG5) + add = true; + break; + + case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB: + if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5) + add = true; + break; + + case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB: + if (tag == TAG_PCSG) + add = true; + break; + + case D3D_BLOB_ALL_SIGNATURE_BLOB: + if (tag == TAG_ISGN || tag == TAG_OSGN || tag == TAG_OSG5 || tag == TAG_PCSG) + add = true; + break; + + case D3D_BLOB_DEBUG_INFO: + if (tag == TAG_SDBG) + add = true; + break; + + case D3D_BLOB_LEGACY_SHADER: + if (tag == TAG_AON9) + add = true; + break; + + case D3D_BLOB_XNA_PREPASS_SHADER: + if (tag == TAG_XNAP) + add = true; + break; + + case D3D_BLOB_XNA_SHADER: + if (tag == TAG_XNAS) + add = true; + break; + + default: + FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3d_blob_part(part)); + break; + } + + TRACE("%s tag %s.\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4)); + + return add; +} + +static HRESULT get_blob_part(const void *data, SIZE_T data_size, + D3D_BLOB_PART part, unsigned int flags, ID3DBlob **blob) +{ + const struct vkd3d_shader_code src_dxbc = {.code = data, .size = data_size}; + struct vkd3d_shader_dxbc_section_desc *sections; + struct vkd3d_shader_dxbc_desc src_dxbc_desc; + struct vkd3d_shader_code dst_dxbc; + unsigned int section_count, i; + HRESULT hr; + int ret; + + if (!data || !data_size || flags || !blob) + { + WARN("Invalid arguments: data %p, data_size %"PRIuPTR", flags %#x, blob %p.\n", + data, (uintptr_t)data_size, flags, blob); + return D3DERR_INVALIDCALL; + } + + if (part > D3D_BLOB_TEST_COMPILE_PERF + || (part < D3D_BLOB_TEST_ALTERNATE_SHADER && part > D3D_BLOB_XNA_SHADER)) + { + WARN("Invalid D3D_BLOB_PART %s.\n", debug_d3d_blob_part(part)); + return D3DERR_INVALIDCALL; + } + + if ((ret = vkd3d_shader_parse_dxbc(&src_dxbc, 0, &src_dxbc_desc, NULL)) < 0) + { + WARN("Failed to parse source data, ret %d.\n", ret); + return D3DERR_INVALIDCALL; + } + + if (!(sections = vkd3d_calloc(src_dxbc_desc.section_count, sizeof(*sections)))) + { + ERR("Failed to allocate sections memory.\n"); + vkd3d_shader_free_dxbc(&src_dxbc_desc); + return E_OUTOFMEMORY; + } + + for (i = 0, section_count = 0; i < src_dxbc_desc.section_count; ++i) + { + const struct vkd3d_shader_dxbc_section_desc *src_section = &src_dxbc_desc.sections[i]; + + if (check_blob_part(src_section->tag, part)) + sections[section_count++] = *src_section; + } + + switch (part) + { + case D3D_BLOB_INPUT_SIGNATURE_BLOB: + case D3D_BLOB_OUTPUT_SIGNATURE_BLOB: + case D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB: + case D3D_BLOB_DEBUG_INFO: + case D3D_BLOB_LEGACY_SHADER: + case D3D_BLOB_XNA_PREPASS_SHADER: + case D3D_BLOB_XNA_SHADER: + if (section_count != 1) + section_count = 0; + break; + + case D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB: + if (section_count != 2) + section_count = 0; + break; + + case D3D_BLOB_ALL_SIGNATURE_BLOB: + if (section_count != 3) + section_count = 0; + break; + + default: + FIXME("Unhandled D3D_BLOB_PART %s.\n", debug_d3d_blob_part(part)); + break; + } + + if (!section_count) + { + WARN("Nothing to write into the blob.\n"); + hr = E_FAIL; + goto done; + } + + /* Some parts aren't full DXBCs, they contain only the data. */ + if (section_count == 1 && (part == D3D_BLOB_DEBUG_INFO || part == D3D_BLOB_LEGACY_SHADER + || part == D3D_BLOB_XNA_PREPASS_SHADER || part == D3D_BLOB_XNA_SHADER)) + { + dst_dxbc = sections[0].data; + } + else if ((ret = vkd3d_shader_serialize_dxbc(section_count, sections, &dst_dxbc, NULL)) < 0) + { + WARN("Failed to serialise DXBC, ret %d.\n", ret); + hr = hresult_from_vkd3d_result(ret); + goto done; + } + + if (FAILED(hr = D3DCreateBlob(dst_dxbc.size, blob))) + WARN("Failed to create blob, hr %s.\n", debugstr_hresult(hr)); + else + memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.code, dst_dxbc.size); + if (dst_dxbc.code != sections[0].data.code) + vkd3d_shader_free_shader_code(&dst_dxbc); + +done: + vkd3d_free(sections); + vkd3d_shader_free_dxbc(&src_dxbc_desc); + + return hr; +} + +HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob) +{ + TRACE("data %p, data_size %"PRIuPTR", part %s, flags %#x, blob %p.\n", + data, (uintptr_t)data_size, debug_d3d_blob_part(part), flags, blob); + + return get_blob_part(data, data_size, part, flags, blob); +} + +HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob) +{ + TRACE("data %p, data_size %"PRIuPTR", blob %p.\n", data, (uintptr_t)data_size, blob); + + return get_blob_part(data, data_size, D3D_BLOB_DEBUG_INFO, 0, blob); +} + +HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob) +{ + TRACE("data %p, data_size %"PRIuPTR", blob %p.\n", data, (uintptr_t)data_size, blob); + + return get_blob_part(data, data_size, D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, 0, blob); +} + +HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob) +{ + TRACE("data %p, data_size %"PRIuPTR", blob %p.\n", data, (uintptr_t)data_size, blob); + + return get_blob_part(data, data_size, D3D_BLOB_INPUT_SIGNATURE_BLOB, 0, blob); +} + +HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob) +{ + TRACE("data %p, data_size %"PRIuPTR", blob %p.\n", data, (uintptr_t)data_size, blob); + + return get_blob_part(data, data_size, D3D_BLOB_OUTPUT_SIGNATURE_BLOB, 0, blob); +} + +static bool check_blob_strip(uint32_t tag, uint32_t flags) +{ + bool add = true; + + switch (tag) + { + case TAG_RDEF: + case TAG_STAT: + if (flags & D3DCOMPILER_STRIP_REFLECTION_DATA) + add = false; + break; + + case TAG_SDBG: + if (flags & D3DCOMPILER_STRIP_DEBUG_INFO) + add = false; + break; + + default: + break; + } + + TRACE("%s tag %s.\n", add ? "Add" : "Skip", debugstr_an((const char *)&tag, 4)); + + return add; +} + +HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob) +{ + const struct vkd3d_shader_code src_dxbc = {.code = data, .size = data_size}; + struct vkd3d_shader_dxbc_section_desc *sections; + struct vkd3d_shader_dxbc_desc src_dxbc_desc; + struct vkd3d_shader_code dst_dxbc; + unsigned int section_count, i; + HRESULT hr; + int ret; + + TRACE("data %p, data_size %"PRIuPTR", flags %#x, blob %p.\n", data, (uintptr_t)data_size, flags, blob); + + if (!blob) + { + WARN("Invalid 'blob' pointer specified.\n"); + return E_FAIL; + } + + if (!data || !data_size) + { + WARN("Invalid arguments: data %p, data_size %"PRIuPTR".\n", data, (uintptr_t)data_size); + return D3DERR_INVALIDCALL; + } + + if ((ret = vkd3d_shader_parse_dxbc(&src_dxbc, 0, &src_dxbc_desc, NULL)) < 0) + { + WARN("Failed to parse source data, ret %d.\n", ret); + return D3DERR_INVALIDCALL; + } + + if (!(sections = vkd3d_calloc(src_dxbc_desc.section_count, sizeof(*sections)))) + { + ERR("Failed to allocate sections memory.\n"); + vkd3d_shader_free_dxbc(&src_dxbc_desc); + return E_OUTOFMEMORY; + } + + if (flags & ~(D3DCOMPILER_STRIP_REFLECTION_DATA | D3DCOMPILER_STRIP_DEBUG_INFO)) + FIXME("Unhandled flags %#x.\n", flags); + + for (i = 0, section_count = 0; i < src_dxbc_desc.section_count; ++i) + { + const struct vkd3d_shader_dxbc_section_desc *src_section = &src_dxbc_desc.sections[i]; + + if (check_blob_strip(src_section->tag, flags)) + sections[section_count++] = *src_section; + } + + if ((ret = vkd3d_shader_serialize_dxbc(section_count, sections, &dst_dxbc, NULL)) < 0) + { + WARN("Failed to serialise DXBC, ret %d.\n", ret); + hr = hresult_from_vkd3d_result(ret); + goto done; + } + + if (FAILED(hr = D3DCreateBlob(dst_dxbc.size, blob))) + WARN("Failed to create blob, hr %s.\n", debugstr_hresult(hr)); + else + memcpy(ID3D10Blob_GetBufferPointer(*blob), dst_dxbc.code, dst_dxbc.size); + vkd3d_shader_free_shader_code(&dst_dxbc); + +done: + vkd3d_free(sections); + vkd3d_shader_free_dxbc(&src_dxbc_desc); + + return hr; +} + +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_14}, + }; + + TRACE("data %p, data_size %"PRIuPTR", flags %#x, comments %p, blob %p.\n", + data, (uintptr_t)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/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h new file mode 100644 index 00000000000..11113e1e55e --- /dev/null +++ b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_private.h @@ -0,0 +1,44 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * + * 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 + */ + +#ifndef __VKD3D_UTILS_PRIVATE_H +#define __VKD3D_UTILS_PRIVATE_H + +#ifndef __MINGW32__ +#define WIDL_C_INLINE_WRAPPERS +#endif +#define COBJMACROS +#define NONAMELESSUNION +#define VK_NO_PROTOTYPES +#define CONST_VTABLE + +#include <vkd3d.h> +#include <vkd3d_shader.h> +#include <d3dcompiler.h> + +#include "vkd3d_blob.h" +#include "vkd3d_memory.h" +#include <vkd3d_utils.h> + +#include <inttypes.h> + +#ifndef D3DERR_INVALIDCALL +#define D3DERR_INVALIDCALL _HRESULT_TYPEDEF_(0x8876086c) +#endif + +#endif /* __VKD3D_UTILS_PRIVATE_H */