As per discussion in 606, plumbing constant buffer reflection through vkd3d-shader requires interface design and API documentation for an interface which is inherently quite specific to one format. Instead of wasting time on this interface, just implement RDEF parsing in vkd3d-utils itself. If we change our mind about this, we can always move the implementation to vkd3d-shader anyway.
This does not copy the existing implementation from Wine, because:
* Wine does not validate offsets; adding this changes the parsing code significantly;
* Wine incorrectly handles types, deduplicating them into an rbtree;
* Wine skips several fields which I have been able to find the purpose of.
The implementation is not that complex to begin with, so reimplementing it from scratch is not much work.
-- v7: tests: Add more tests for resource and struct RDEF contents. tests: Test constant and resource reflection via D3DReflect(). vkd3d-shader/tpf: Set the user-packed flag for sm5.0 resources as well. vkd3d-shader/tpf: Write the component count as the column count for structs. vkd3d-shader/tpf: Explicitly write the class and base type for non-numeric types. vkd3d-shader/tpf: Do not write structs with no numeric fields into the RDEF. vkd3d-shader/hlsl: Allocate register reservations for structs as well. vkd3d-shader/tpf: Do not write non-numeric struct fields into the RDEF. vkd3d-utils: Implement ID3D12ShaderReflectionType::GetMemberTypeByIndex(). vkd3d-utils: Implement ID3D12ShaderReflectionVariable::GetType(). vkd3d-utils: Implement ID3D12ShaderReflectionConstantBuffer::GetVariableByIndex(). vkd3d-utils: Parse the RD11 section. vkd3d-utils: Implement ID3D12ShaderReflection::GetConstantBufferByIndex().
From: Zebediah Figura zfigura@codeweavers.com
--- include/private/vkd3d_memory.h | 9 ++ libs/vkd3d-utils/reflection.c | 243 ++++++++++++++++++++++++++++++++- 2 files changed, 246 insertions(+), 6 deletions(-)
diff --git a/include/private/vkd3d_memory.h b/include/private/vkd3d_memory.h index 8a2edb100..d89f741b5 100644 --- a/include/private/vkd3d_memory.h +++ b/include/private/vkd3d_memory.h @@ -65,6 +65,15 @@ static inline char *vkd3d_strdup(const char *string) return ptr; }
+static inline void *vkd3d_memdup(const void *mem, size_t size) +{ + void *ptr; + + if ((ptr = vkd3d_malloc(size))) + memcpy(ptr, mem, size); + return ptr; +} + bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size);
#endif /* __VKD3D_MEMORY_H */ diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c index 1973bda76..1e217d8d7 100644 --- a/libs/vkd3d-utils/reflection.c +++ b/libs/vkd3d-utils/reflection.c @@ -21,14 +21,79 @@ #include <vkd3d_d3dcommon.h> #include <vkd3d_d3d12shader.h>
+struct d3d12_buffer +{ + ID3D12ShaderReflectionConstantBuffer ID3D12ShaderReflectionConstantBuffer_iface; + D3D12_SHADER_BUFFER_DESC desc; +}; + 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; };
+static struct d3d12_buffer null_buffer; + +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) +{ + FIXME("iface %p, index %u, stub!\n", iface, index); + + return NULL; +} + +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); @@ -72,6 +137,10 @@ static ULONG STDMETHODCALLTYPE d3d12_reflection_Release(ID3D12ShaderReflection *
if (!refcount) { + for (UINT i = 0; i < reflection->desc.ConstantBuffers; ++i) + vkd3d_free((void *)reflection->buffers[i].desc.Name); + vkd3d_free(reflection->buffers); + vkd3d_shader_free_scan_signature_info(&reflection->signature_info); free(reflection); } @@ -87,9 +156,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetDesc(ID3D12ShaderReflection
FIXME("iface %p, desc %p partial stub!\n", iface, desc);
- desc->InputParameters = reflection->signature_info.input.element_count; - desc->OutputParameters = reflection->signature_info.output.element_count; - desc->PatchConstantParameters = reflection->signature_info.patch_constant.element_count; + *desc = reflection->desc;
return S_OK; } @@ -97,9 +164,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetDesc(ID3D12ShaderReflection static struct ID3D12ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3d12_reflection_GetConstantBufferByIndex( ID3D12ShaderReflection *iface, UINT index) { - FIXME("iface %p, index %u stub!\n", iface, index); + struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface);
- return NULL; + 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( @@ -287,9 +362,128 @@ static const struct ID3D12ShaderReflectionVtbl d3d12_reflection_vtbl = 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_buffer +{ + uint32_t name_offset; + uint32_t var_count; + uint32_t vars_offset; + uint32_t size; + uint32_t flags; + uint32_t type; +}; + +static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_buffer *rdef_buffer, + const struct vkd3d_shader_code *section) +{ + 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; + + return S_OK; +} + +static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3d_shader_code *section) +{ + const struct rdef_header *header; + HRESULT hr; + + if (!(header = get_data_ptr(section, 0, 1, sizeof(*header)))) + 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))) + return hr; + } + } + + 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; @@ -301,7 +495,44 @@ static HRESULT d3d12_reflection_init(struct d3d12_reflection *reflection, const compile_info.next = &reflection->signature_info; reflection->signature_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO;
- return hresult_from_vkd3d_result(vkd3d_shader_scan(&compile_info, NULL)); + 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))) + { + vkd3d_shader_free_scan_signature_info(&reflection->signature_info); + vkd3d_shader_free_dxbc(&dxbc_desc); + return hr; + } + found_rdef = true; + } + } + + 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; }
HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection)
From: Zebediah Figura zfigura@codeweavers.com
--- include/private/vkd3d_common.h | 2 ++ libs/vkd3d-utils/reflection.c | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index dc0b2e172..4cad08e1e 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -72,6 +72,8 @@ #define TAG_XNAP VKD3D_MAKE_TAG('X', 'N', 'A', 'P') #define TAG_XNAS VKD3D_MAKE_TAG('X', 'N', 'A', 'S')
+#define TAG_RD11_REVERSE 0x25441313 + static inline uint64_t align(uint64_t addr, size_t alignment) { return (addr + (alignment - 1)) & ~(alignment - 1); diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c index 1e217d8d7..e671a37b9 100644 --- a/libs/vkd3d-utils/reflection.c +++ b/libs/vkd3d-utils/reflection.c @@ -416,6 +416,19 @@ struct rdef_header 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; @@ -449,11 +462,45 @@ static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_ static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3d_shader_code *section) { 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->zero) + { + FIXME("Unexpected field %#x.\n", rd11->zero); + return E_INVALIDARG; + } + } + reflection->desc.ConstantBuffers = header->buffer_count;
if (header->buffer_count)
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-utils/reflection.c | 179 +++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c index e671a37b9..41fb6413e 100644 --- a/libs/vkd3d-utils/reflection.c +++ b/libs/vkd3d-utils/reflection.c @@ -21,10 +21,19 @@ #include <vkd3d_d3dcommon.h> #include <vkd3d_d3d12shader.h>
+struct d3d12_variable +{ + ID3D12ShaderReflectionVariable ID3D12ShaderReflectionVariable_iface; + D3D12_SHADER_VARIABLE_DESC desc; + struct d3d12_buffer *buffer; +}; + struct d3d12_buffer { ID3D12ShaderReflectionConstantBuffer ID3D12ShaderReflectionConstantBuffer_iface; D3D12_SHADER_BUFFER_DESC desc; + + struct d3d12_variable *variables; };
struct d3d12_reflection @@ -40,6 +49,71 @@ struct d3d12_reflection };
static struct d3d12_buffer null_buffer; +static struct d3d12_variable null_variable; + +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) +{ + FIXME("iface %p, stub!\n", iface); + + return NULL; +} + +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) { @@ -72,9 +146,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_buffer_GetDesc( static ID3D12ShaderReflectionVariable * STDMETHODCALLTYPE d3d12_buffer_GetVariableByIndex( ID3D12ShaderReflectionConstantBuffer *iface, UINT index) { - FIXME("iface %p, index %u, stub!\n", iface, index); + struct d3d12_buffer *buffer = impl_from_ID3D12ShaderReflectionConstantBuffer(iface);
- return NULL; + 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( @@ -138,7 +220,19 @@ static ULONG STDMETHODCALLTYPE d3d12_reflection_Release(ID3D12ShaderReflection * if (!refcount) { for (UINT i = 0; i < reflection->desc.ConstantBuffers; ++i) - vkd3d_free((void *)reflection->buffers[i].desc.Name); + { + struct d3d12_buffer *buffer = &reflection->buffers[i]; + + for (UINT j = 0; j < buffer->desc.Variables; ++j) + { + struct d3d12_variable *variable = &buffer->variables[j]; + + 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);
vkd3d_shader_free_scan_signature_info(&reflection->signature_info); @@ -439,8 +533,56 @@ struct rdef_buffer 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; +}; + +static HRESULT d3d12_variable_init(struct d3d12_variable *variable, + const struct rdef_variable *rdef_variable, const struct vkd3d_shader_code *section) +{ + 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 S_OK; +} + static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_buffer *rdef_buffer, - const struct vkd3d_shader_code *section) + const struct vkd3d_shader_code *section, uint32_t variable_size) { HRESULT hr; char *name; @@ -456,11 +598,31 @@ static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_ 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))) + 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); const struct rdef_header *header; const struct rdef_rd11 *rd11; HRESULT hr; @@ -494,6 +656,13 @@ static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3 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->zero) { FIXME("Unexpected field %#x.\n", rd11->zero); @@ -516,7 +685,7 @@ static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3
for (uint32_t i = 0; i < header->buffer_count; ++i) { - if ((hr = d3d12_buffer_init(&reflection->buffers[i], &rdef_buffers[i], section))) + if ((hr = d3d12_buffer_init(&reflection->buffers[i], &rdef_buffers[i], section, variable_size))) return hr; } }
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-utils/reflection.c | 208 ++++++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c index 41fb6413e..a33d3aa46 100644 --- a/libs/vkd3d-utils/reflection.c +++ b/libs/vkd3d-utils/reflection.c @@ -21,11 +21,19 @@ #include <vkd3d_d3dcommon.h> #include <vkd3d_d3d12shader.h>
+struct d3d12_type +{ + ID3D12ShaderReflectionType ID3D12ShaderReflectionType_iface; + D3D12_SHADER_TYPE_DESC desc; +}; + struct d3d12_variable { ID3D12ShaderReflectionVariable ID3D12ShaderReflectionVariable_iface; D3D12_SHADER_VARIABLE_DESC desc; struct d3d12_buffer *buffer; + + struct d3d12_type type; };
struct d3d12_buffer @@ -50,6 +58,129 @@ struct d3d12_reflection
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) +{ + FIXME("iface %p, index %u, stub!\n", iface, index); + + return NULL; +} + +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_variable *impl_from_ID3D12ShaderReflectionVariable(ID3D12ShaderReflectionVariable *iface) { @@ -82,9 +213,14 @@ static HRESULT STDMETHODCALLTYPE d3d12_variable_GetDesc( static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_variable_GetType( ID3D12ShaderReflectionVariable *iface) { - FIXME("iface %p, stub!\n", iface); + struct d3d12_variable *variable = impl_from_ID3D12ShaderReflectionVariable(iface);
- return NULL; + 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( @@ -210,6 +346,11 @@ static ULONG STDMETHODCALLTYPE d3d12_reflection_AddRef(ID3D12ShaderReflection *i return refcount; }
+static void free_type(struct d3d12_type *type) +{ + vkd3d_free((void *)type->desc.Name); +} + static ULONG STDMETHODCALLTYPE d3d12_reflection_Release(ID3D12ShaderReflection *iface) { struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface); @@ -227,6 +368,7 @@ static ULONG STDMETHODCALLTYPE d3d12_reflection_Release(ID3D12ShaderReflection * { struct d3d12_variable *variable = &buffer->variables[j];
+ free_type(&variable->type); vkd3d_free((void *)variable->desc.DefaultValue); vkd3d_free((void *)variable->desc.Name); } @@ -547,8 +689,50 @@ struct rdef_variable uint32_t sampler_count; };
-static HRESULT d3d12_variable_init(struct d3d12_variable *variable, - const struct rdef_variable *rdef_variable, const struct vkd3d_shader_code *section) +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; +}; + +static HRESULT d3d12_type_init(struct d3d12_type *type, uint32_t type_offset, + uint32_t type_size, const struct vkd3d_shader_code *section) +{ + 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.Name = name; + + 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; @@ -578,11 +762,11 @@ static HRESULT d3d12_variable_init(struct d3d12_variable *variable, return E_OUTOFMEMORY; }
- return S_OK; + return d3d12_type_init(&variable->type, rdef_variable->type_offset, type_size, section); }
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) + const struct vkd3d_shader_code *section, uint32_t variable_size, uint32_t type_size) { HRESULT hr; char *name; @@ -613,7 +797,7 @@ static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_ normalized_variable.sampler_binding = ~0u; memcpy(&normalized_variable, rdef_variable, variable_size);
- if ((hr = d3d12_variable_init(&buffer->variables[i], &normalized_variable, section))) + if ((hr = d3d12_variable_init(&buffer->variables[i], &normalized_variable, section, type_size))) return hr; }
@@ -623,6 +807,7 @@ static HRESULT d3d12_buffer_init(struct d3d12_buffer *buffer, const struct rdef_ 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 type_size = offsetof(struct rdef_type, unknown); const struct rdef_header *header; const struct rdef_rd11 *rd11; HRESULT hr; @@ -663,6 +848,13 @@ static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3 } variable_size = rd11->variable_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); @@ -685,7 +877,7 @@ static HRESULT parse_rdef(struct d3d12_reflection *reflection, const struct vkd3
for (uint32_t i = 0; i < header->buffer_count; ++i) { - if ((hr = d3d12_buffer_init(&reflection->buffers[i], &rdef_buffers[i], section, variable_size))) + if ((hr = d3d12_buffer_init(&reflection->buffers[i], &rdef_buffers[i], section, variable_size, type_size))) return hr; } }
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-utils/reflection.c | 57 ++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c index a33d3aa46..920cc3717 100644 --- a/libs/vkd3d-utils/reflection.c +++ b/libs/vkd3d-utils/reflection.c @@ -25,6 +25,13 @@ 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 @@ -91,9 +98,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_type_GetDesc( static ID3D12ShaderReflectionType * STDMETHODCALLTYPE d3d12_type_GetMemberTypeByIndex( ID3D12ShaderReflectionType *iface, UINT index) { - FIXME("iface %p, index %u, stub!\n", iface, index); + struct d3d12_type *type = impl_from_ID3D12ShaderReflectionType(iface);
- return NULL; + 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( @@ -348,6 +363,9 @@ static ULONG STDMETHODCALLTYPE d3d12_reflection_AddRef(ID3D12ShaderReflection *i
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); }
@@ -703,8 +721,15 @@ struct rdef_type uint32_t name_offset; };
-static HRESULT d3d12_type_init(struct d3d12_type *type, uint32_t type_offset, - uint32_t type_size, const struct vkd3d_shader_code *section) +struct rdef_field +{ + uint32_t name_offset; + uint32_t type_offset; + uint32_t offset; +}; + +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; @@ -726,8 +751,30 @@ static HRESULT d3d12_type_init(struct d3d12_type *type, uint32_t type_offset, 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; }
@@ -762,7 +809,7 @@ static HRESULT d3d12_variable_init(struct d3d12_variable *variable, const struct return E_OUTOFMEMORY; }
- return d3d12_type_init(&variable->type, rdef_variable->type_offset, type_size, section); + 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,
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 78 +++++++---------------------------------- 1 file changed, 12 insertions(+), 66 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 3be4e40ab..a80ee0699 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2997,18 +2997,16 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) return D3D_SVC_MATRIX_COLUMNS; else return D3D_SVC_MATRIX_ROWS; - case HLSL_CLASS_OBJECT: - return D3D_SVC_OBJECT; case HLSL_CLASS_SCALAR: return D3D_SVC_SCALAR; case HLSL_CLASS_STRUCT: return D3D_SVC_STRUCT; case HLSL_CLASS_VECTOR: return D3D_SVC_VECTOR; - default: - ERR("Invalid class %#x.\n", type->class); - vkd3d_unreachable(); + case HLSL_CLASS_OBJECT: + break; } + vkd3d_unreachable(); }
static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) @@ -3024,68 +3022,10 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) return D3D_SVT_FLOAT; case HLSL_TYPE_INT: return D3D_SVT_INT; - case HLSL_TYPE_PIXELSHADER: - return D3D_SVT_PIXELSHADER; - case HLSL_TYPE_SAMPLER: - switch (type->sampler_dim) - { - case HLSL_SAMPLER_DIM_1D: - return D3D_SVT_SAMPLER1D; - case HLSL_SAMPLER_DIM_2D: - return D3D_SVT_SAMPLER2D; - case HLSL_SAMPLER_DIM_3D: - return D3D_SVT_SAMPLER3D; - case HLSL_SAMPLER_DIM_CUBE: - return D3D_SVT_SAMPLERCUBE; - case HLSL_SAMPLER_DIM_GENERIC: - return D3D_SVT_SAMPLER; - default: - vkd3d_unreachable(); - } - break; - case HLSL_TYPE_STRING: - return D3D_SVT_STRING; - case HLSL_TYPE_TEXTURE: - switch (type->sampler_dim) - { - case HLSL_SAMPLER_DIM_1D: - return D3D_SVT_TEXTURE1D; - case HLSL_SAMPLER_DIM_2D: - return D3D_SVT_TEXTURE2D; - case HLSL_SAMPLER_DIM_2DMS: - return D3D_SVT_TEXTURE2DMS; - case HLSL_SAMPLER_DIM_3D: - return D3D_SVT_TEXTURE3D; - case HLSL_SAMPLER_DIM_CUBE: - return D3D_SVT_TEXTURECUBE; - case HLSL_SAMPLER_DIM_GENERIC: - return D3D_SVT_TEXTURE; - default: - vkd3d_unreachable(); - } - break; case HLSL_TYPE_UINT: return D3D_SVT_UINT; - case HLSL_TYPE_VERTEXSHADER: - return D3D_SVT_VERTEXSHADER; case HLSL_TYPE_VOID: return D3D_SVT_VOID; - case HLSL_TYPE_UAV: - switch (type->sampler_dim) - { - case HLSL_SAMPLER_DIM_1D: - return D3D_SVT_RWTEXTURE1D; - case HLSL_SAMPLER_DIM_2D: - return D3D_SVT_RWTEXTURE2D; - case HLSL_SAMPLER_DIM_3D: - return D3D_SVT_RWTEXTURE3D; - case HLSL_SAMPLER_DIM_1DARRAY: - return D3D_SVT_RWTEXTURE1DARRAY; - case HLSL_SAMPLER_DIM_2DARRAY: - return D3D_SVT_RWTEXTURE2DARRAY; - default: - vkd3d_unreachable(); - } default: vkd3d_unreachable(); } @@ -3111,22 +3051,28 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
if (array_type->class == HLSL_CLASS_STRUCT) { - field_count = array_type->e.record.field_count;
- for (i = 0; i < field_count; ++i) + for (i = 0; i < array_type->e.record.field_count; ++i) { struct hlsl_struct_field *field = &array_type->e.record.fields[i];
+ if (!field->type->reg_size[HLSL_REGSET_NUMERIC]) + continue; + field->name_bytecode_offset = put_string(buffer, field->name); write_sm4_type(ctx, buffer, field->type); + ++field_count; }
fields_offset = bytecode_align(buffer);
- for (i = 0; i < field_count; ++i) + for (i = 0; i < array_type->e.record.field_count; ++i) { struct hlsl_struct_field *field = &array_type->e.record.fields[i];
+ if (!field->type->reg_size[HLSL_REGSET_NUMERIC]) + continue; + put_u32(buffer, field->name_bytecode_offset); put_u32(buffer, field->type->bytecode_offset); put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]);
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 3 --- tests/hlsl/register-reservations-resources.shader_test | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 307f86f55..cc2343b35 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -3457,9 +3457,6 @@ static void allocate_register_reservations(struct hlsl_ctx *ctx) { unsigned int r;
- if (!hlsl_type_is_resource(var->data_type)) - continue; - if (var->reg_reservation.reg_type) { for (r = 0; r <= HLSL_REGSET_LAST_OBJECT; ++r) diff --git a/tests/hlsl/register-reservations-resources.shader_test b/tests/hlsl/register-reservations-resources.shader_test index 5b53a625a..d130b3291 100644 --- a/tests/hlsl/register-reservations-resources.shader_test +++ b/tests/hlsl/register-reservations-resources.shader_test @@ -198,7 +198,7 @@ filter linear linear linear address clamp clamp clamp
% If a struct spans many object register sets and one is reserved, all other used object register sets must be. -[pixel shader fail(sm<6) todo] +[pixel shader fail(sm<6)] struct { Texture2D tex; @@ -242,4 +242,4 @@ float4 main() : sv_target
[test] draw quad -todo(sm<6) probe all rgba (1.0, 1.0, 1.0, 99.0) +probe all rgba (1.0, 1.0, 1.0, 99.0)
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index a80ee0699..678f43260 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3469,8 +3469,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && var->buffer == cbuffer - && var->data_type->class != HLSL_CLASS_OBJECT) + if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC]) ++var_count; }
@@ -3504,8 +3503,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && var->buffer == cbuffer - && var->data_type->class != HLSL_CLASS_OBJECT) + if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC]) { uint32_t flags = 0;
@@ -3532,8 +3530,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) j = 0; LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && var->buffer == cbuffer - && var->data_type->class != HLSL_CLASS_OBJECT) + if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC]) { const unsigned int var_size = (profile->major_version >= 5 ? 10 : 6); size_t var_offset = vars_start + j * var_size * sizeof(uint32_t);
From: Zebediah Figura zfigura@codeweavers.com
Avoid relying on that information being stored in the hlsl_type. --- libs/vkd3d-shader/tpf.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 678f43260..f066911a8 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2989,8 +2989,6 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) { switch (type->class) { - case HLSL_CLASS_ARRAY: - return sm4_class(type->e.array.type); case HLSL_CLASS_MATRIX: assert(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK); if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR) @@ -2999,10 +2997,11 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) return D3D_SVC_MATRIX_ROWS; case HLSL_CLASS_SCALAR: return D3D_SVC_SCALAR; - case HLSL_CLASS_STRUCT: - return D3D_SVC_STRUCT; case HLSL_CLASS_VECTOR: return D3D_SVC_VECTOR; + + case HLSL_CLASS_ARRAY: + case HLSL_CLASS_STRUCT: case HLSL_CLASS_OBJECT: break; } @@ -3024,8 +3023,6 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) return D3D_SVT_INT; case HLSL_TYPE_UINT: return D3D_SVT_UINT; - case HLSL_TYPE_VOID: - return D3D_SVT_VOID; default: vkd3d_unreachable(); } @@ -3077,9 +3074,14 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b put_u32(buffer, field->type->bytecode_offset); put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]); } + + type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); + } + else + { + type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); }
- type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(type), sm4_base_type(type))); put_u32(buffer, vkd3d_make_u32(type->dimy, type->dimx)); put_u32(buffer, vkd3d_make_u32(array_size, field_count)); put_u32(buffer, fields_offset);
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index f066911a8..517493988 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3033,8 +3033,8 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type); const char *name = array_type->name ? array_type->name : "<unnamed>"; const struct hlsl_profile_info *profile = ctx->profile; - unsigned int field_count = 0, array_size = 0; - size_t fields_offset = 0, name_offset = 0; + unsigned int array_size = 0; + size_t name_offset = 0; size_t i;
if (type->bytecode_offset) @@ -3048,6 +3048,8 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
if (array_type->class == HLSL_CLASS_STRUCT) { + unsigned int field_count = 0; + size_t fields_offset = 0;
for (i = 0; i < array_type->e.record.field_count; ++i) { @@ -3074,18 +3076,20 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b put_u32(buffer, field->type->bytecode_offset); put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]); } - type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); + put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type))); + put_u32(buffer, vkd3d_make_u32(array_size, field_count)); + put_u32(buffer, fields_offset); } else { + assert(array_type->class <= HLSL_CLASS_LAST_NUMERIC); type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); + put_u32(buffer, vkd3d_make_u32(array_type->dimy, array_type->dimx)); + put_u32(buffer, vkd3d_make_u32(array_size, 0)); + put_u32(buffer, 1); }
- put_u32(buffer, vkd3d_make_u32(type->dimy, type->dimx)); - put_u32(buffer, vkd3d_make_u32(array_size, field_count)); - put_u32(buffer, fields_offset); - if (profile->major_version >= 5) { put_u32(buffer, 0); /* FIXME: unknown */
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 517493988..94a9e846e 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3280,7 +3280,7 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
extern_resources[*count].name = name; extern_resources[*count].data_type = component_type; - extern_resources[*count].is_user_packed = false; + extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type;
extern_resources[*count].regset = regset; extern_resources[*count].id = var->regs[regset].id + regset_offset;
From: Zebediah Figura zfigura@codeweavers.com
Ported from Wine. --- tests/hlsl_d3d12.c | 290 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+)
diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index b2273ffbc..471ad9294 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -1318,6 +1318,295 @@ static void test_get_blob_part(void) ok(!refcount, "Got refcount %u.\n", refcount); }
+static void check_type_desc_(int line, const D3D12_SHADER_TYPE_DESC *type, const D3D12_SHADER_TYPE_DESC *expect) +{ + ok_(line)(type->Class == expect->Class, "Got class %#x.\n", type->Class); + ok_(line)(type->Type == expect->Type, "Got type %#x.\n", type->Type); + ok_(line)(type->Rows == expect->Rows, "Got %u rows.\n", type->Rows); + ok_(line)(type->Columns == expect->Columns, "Got %u columns.\n", type->Columns); + ok_(line)(type->Elements == expect->Elements, "Got %u elements.\n", type->Elements); + ok_(line)(type->Members == expect->Members, "Got %u members.\n", type->Members); + ok_(line)(type->Offset == expect->Offset, "Got %u members.\n", type->Members); + ok_(line)(!strcmp(type->Name, expect->Name), "Got name "%s".\n", type->Name); +} +#define check_type_desc(a, b) check_type_desc_(__LINE__, a, b) + +static void test_reflection(void) +{ + unsigned int refcount; + HRESULT hr; + + static const char vs_source[] = + "typedef uint uint_t;\n" + "float m;\n" + "\n" + "cbuffer b1\n" + "{\n" + " float a;\n" + " float2 b;\n" + " float4 c;\n" + " float d;\n" + " struct\n" + " {\n" + " float4 a;\n" + " float b;\n" + " float c;\n" + " } s;\n" + /* In direct contradiction to the documentation, this does not align. */ + " bool g;\n" + " float h[2];\n" + " int i;\n" + " uint_t j;\n" + " float3x1 k;\n" + " row_major float3x1 l;\n" + "#pragma pack_matrix(row_major)\n" + " float3x1 o;\n" + " float4 p;\n" + " float q;\n" + " struct r_name {float a;} r;\n" + " column_major float3x1 t;\n" + "};\n" + "\n" + "cbuffer b5 : register(b5)\n" + "{\n" + " float4 u;\n" + "}\n" + "\n" + "float4 main(uniform float4 n) : SV_POSITION\n" + "{\n" + " return o._31 + m + n + u;\n" + "}"; + + struct shader_variable + { + D3D12_SHADER_VARIABLE_DESC var_desc; + D3D12_SHADER_TYPE_DESC type_desc; + const D3D12_SHADER_TYPE_DESC *field_types; + }; + + struct shader_buffer + { + D3D12_SHADER_BUFFER_DESC desc; + const struct shader_variable *vars; + }; + + static const D3D12_SHADER_TYPE_DESC s_field_types[] = + { + {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}, + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 16, "float"}, + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 20, "float"}, + }; + + static const D3D12_SHADER_TYPE_DESC r_field_types[] = + { + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}, + }; + + static const struct shader_variable globals_vars = + {{"m", 0, 4, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}}; + static const struct shader_variable params_vars = + {{"n", 0, 16, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}; + static const struct shader_variable buffer_vars[] = + { + {{"a", 0, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}}, + {{"b", 4, 8, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 2, 0, 0, 0, "float2"}}, + {{"c", 16, 16, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}, + {{"d", 32, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}}, + {{"s", 48, 24, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 6, 0, ARRAY_SIZE(s_field_types), 0, "<unnamed>"}, s_field_types}, + {{"g", 72, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_BOOL, 1, 1, 0, 0, 0, "bool"}}, + {{"h", 80, 20, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 2, 0, 0, "float"}}, + {{"i", 100, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_INT, 1, 1, 0, 0, 0, "int"}}, + {{"j", 104, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_UINT, 1, 1, 0, 0, 0, "uint_t"}}, + {{"k", 112, 12, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, + {{"l", 128, 36, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_ROWS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, + {{"o", 176, 36, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_ROWS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, + {{"p", 224, 16, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}, + {{"q", 240, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}}, + {{"r", 256, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 1, 0, ARRAY_SIZE(r_field_types), 0, "r_name"}, r_field_types}, + {{"t", 260, 12, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, + }; + static const struct shader_variable b5_vars = + {{"u", 0, 16, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}; + + static const struct shader_buffer vs_buffers[] = + { + {{"$Globals", D3D_CT_CBUFFER, 1, 16}, &globals_vars}, + {{"$Params", D3D_CT_CBUFFER, 1, 16}, ¶ms_vars}, + {{"b1", D3D_CT_CBUFFER, ARRAY_SIZE(buffer_vars), 272}, buffer_vars}, + {{"b5", D3D_CT_CBUFFER, 1, 16}, &b5_vars}, + }; + + static const D3D12_SHADER_INPUT_BIND_DESC vs_bindings[] = + { + {"$Globals", D3D_SIT_CBUFFER, 0, 1}, + {"$Params", D3D_SIT_CBUFFER, 1, 1}, + {"b1", D3D_SIT_CBUFFER, 2, 1}, + {"b5", D3D_SIT_CBUFFER, 5, 1, D3D_SIF_USERPACKED}, + }; + + static const char ps_source[] = + "texture2D a;\n" + "sampler c {};\n" + "SamplerState d {};\n" + "sampler e\n" + "{\n" + " Texture = a;\n" + " foo = bar + 2;\n" + "};\n" + "SamplerState f\n" + "{\n" + " Texture = a;\n" + " foo = bar + 2;\n" + "};\n" + "sampler2D g;\n" + "sampler b : register(s5);\n" + "float4 main(float2 pos : texcoord) : SV_TARGET\n" + "{\n" + " return a.Sample(b, pos) + a.Sample(c, pos) + a.Sample(d, pos) + tex2D(f, pos) + tex2D(e, pos)" + " + tex2D(g, pos);\n" + "}"; + + static const D3D12_SHADER_INPUT_BIND_DESC ps_bindings[] = + { + {"c", D3D_SIT_SAMPLER, 0, 1}, + {"d", D3D_SIT_SAMPLER, 1, 1}, + {"e", D3D_SIT_SAMPLER, 2, 1}, + {"f", D3D_SIT_SAMPLER, 3, 1}, + {"g", D3D_SIT_SAMPLER, 4, 1}, + {"b", D3D_SIT_SAMPLER, 5, 1, D3D_SIF_USERPACKED}, + {"f", D3D_SIT_TEXTURE, 0, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, + {"e", D3D_SIT_TEXTURE, 1, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, + {"g", D3D_SIT_TEXTURE, 2, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, + {"a", D3D_SIT_TEXTURE, 3, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, + }; + + static const struct + { + const char *source; + const char *profile; + const D3D12_SHADER_INPUT_BIND_DESC *bindings; + size_t binding_count; + const struct shader_buffer *buffers; + size_t buffer_count; + } + tests[] = + { + {vs_source, "vs_5_0", vs_bindings, ARRAY_SIZE(vs_bindings), vs_buffers, ARRAY_SIZE(vs_buffers)}, + {ps_source, "ps_5_0", ps_bindings, ARRAY_SIZE(ps_bindings)}, + }; + + for (unsigned int t = 0; t < ARRAY_SIZE(tests); ++t) + { + ID3D10Blob *code = compile_shader_flags(tests[t].source, + tests[t].profile, D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY); + ID3D12ShaderReflection *reflection; + D3D12_SHADER_DESC shader_desc; + + hr = D3DReflect(ID3D10Blob_GetBufferPointer(code), ID3D10Blob_GetBufferSize(code), + &IID_ID3D12ShaderReflection, (void **)&reflection); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = ID3D12ShaderReflection_GetDesc(reflection, &shader_desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(shader_desc.ConstantBuffers == tests[t].buffer_count, "Got %u buffers.\n", shader_desc.ConstantBuffers); + todo ok(shader_desc.BoundResources == tests[t].binding_count, "Got %u resources.\n", shader_desc.BoundResources); + + for (unsigned int i = 0; i < shader_desc.ConstantBuffers; ++i) + { + const struct shader_buffer *expect_buffer = &tests[t].buffers[i]; + ID3D12ShaderReflectionConstantBuffer *cbuffer; + D3D12_SHADER_BUFFER_DESC buffer_desc; + + vkd3d_test_push_context("Buffer %u", i); + + cbuffer = ID3D12ShaderReflection_GetConstantBufferByIndex(reflection, i); + hr = ID3D12ShaderReflectionConstantBuffer_GetDesc(cbuffer, &buffer_desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!strcmp(buffer_desc.Name, expect_buffer->desc.Name), "Got name "%s".\n", buffer_desc.Name); + ok(buffer_desc.Type == expect_buffer->desc.Type, "Got type %#x.\n", buffer_desc.Type); + ok(buffer_desc.Variables == expect_buffer->desc.Variables, "Got %u variables.\n", buffer_desc.Variables); + ok(buffer_desc.Size == expect_buffer->desc.Size, "Got size %u.\n", buffer_desc.Size); + ok(buffer_desc.uFlags == expect_buffer->desc.uFlags, "Got flags %#x.\n", buffer_desc.uFlags); + + for (unsigned int j = 0; j < buffer_desc.Variables; ++j) + { + const struct shader_variable *expect = &expect_buffer->vars[j]; + ID3D12ShaderReflectionType *type, *field; + ID3D12ShaderReflectionVariable *var; + D3D12_SHADER_VARIABLE_DESC var_desc; + D3D12_SHADER_TYPE_DESC type_desc; + + vkd3d_test_push_context("Variable %u", j); + + var = ID3D12ShaderReflectionConstantBuffer_GetVariableByIndex(cbuffer, j); + hr = ID3D12ShaderReflectionVariable_GetDesc(var, &var_desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!strcmp(var_desc.Name, expect->var_desc.Name), "Got name "%s".\n", var_desc.Name); + ok(var_desc.StartOffset == expect->var_desc.StartOffset, "Got offset %u.\n", var_desc.StartOffset); + ok(var_desc.Size == expect->var_desc.Size, "Got size %u.\n", var_desc.Size); + ok(var_desc.uFlags == expect->var_desc.uFlags, "Got flags %#x.\n", var_desc.uFlags); + ok(!var_desc.DefaultValue, "Got default value %p.\n", var_desc.DefaultValue); + todo ok(var_desc.StartTexture == expect->var_desc.StartTexture, + "Got texture offset %u.\n", var_desc.StartTexture); + ok(var_desc.TextureSize == expect->var_desc.TextureSize, + "Got texture size %u.\n", var_desc.TextureSize); + todo ok(var_desc.StartSampler == expect->var_desc.StartSampler, + "Got sampler offset %u.\n", var_desc.StartSampler); + ok(var_desc.SamplerSize == expect->var_desc.SamplerSize, + "Got sampler size %u.\n", var_desc.SamplerSize); + + type = ID3D12ShaderReflectionVariable_GetType(var); + hr = ID3D12ShaderReflectionType_GetDesc(type, &type_desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + check_type_desc(&type_desc, &expect->type_desc); + + for (unsigned int k = 0; k < type_desc.Members; ++k) + { + vkd3d_test_push_context("Field %u", k); + + field = ID3D12ShaderReflectionType_GetMemberTypeByIndex(type, k); + hr = ID3D12ShaderReflectionType_GetDesc(field, &type_desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + check_type_desc(&type_desc, &expect->field_types[k]); + + vkd3d_test_pop_context(); + } + + vkd3d_test_pop_context(); + } + + vkd3d_test_pop_context(); + } + + for (unsigned int i = 0; i < shader_desc.BoundResources; ++i) + { + const D3D12_SHADER_INPUT_BIND_DESC *expect = &tests[t].bindings[i]; + D3D12_SHADER_INPUT_BIND_DESC desc; + + vkd3d_test_push_context("Binding %u", i); + + hr = ID3D12ShaderReflection_GetResourceBindingDesc(reflection, i, &desc); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + ok(!strcmp(desc.Name, expect->Name), "Got name "%s".\n", desc.Name); + ok(desc.Type == expect->Type, "Got type %#x.\n", desc.Type); + ok(desc.BindPoint == expect->BindPoint, "Got bind point %u.\n", desc.BindPoint); + ok(desc.BindCount == expect->BindCount, "Got bind count %u.\n", desc.BindCount); + todo_if ((expect->uFlags & D3D_SIF_USERPACKED) && expect->Type != D3D_SIT_CBUFFER) + ok(desc.uFlags == expect->uFlags, "Got flags %#x.\n", desc.uFlags); + ok(desc.ReturnType == expect->ReturnType, "Got return type %#x.\n", desc.ReturnType); + ok(desc.Dimension == expect->Dimension, "Got dimension %#x.\n", desc.Dimension); + ok(desc.NumSamples == expect->NumSamples, "Got multisample count %u.\n", desc.NumSamples); + + vkd3d_test_pop_context(); + } + + ID3D10Blob_Release(code); + refcount = ID3D12ShaderReflection_Release(reflection); + ok(!refcount, "Got unexpected refcount %u.\n", refcount); + } +} + static void check_signature_element_(int line, const D3D12_SIGNATURE_PARAMETER_DESC *desc, const D3D12_SIGNATURE_PARAMETER_DESC *expect) { @@ -1615,6 +1904,7 @@ START_TEST(hlsl_d3d12) run_test(test_thread_id); run_test(test_create_blob); run_test(test_get_blob_part); + run_test(test_reflection); run_test(test_signature_reflection); run_test(test_disassemble_shader); }
From: Zebediah Figura zfigura@codeweavers.com
--- tests/hlsl_d3d12.c | 71 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 10 deletions(-)
diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index 471ad9294..7719930c9 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -1363,7 +1363,7 @@ static void test_reflection(void) " float3x1 o;\n" " float4 p;\n" " float q;\n" - " struct r_name {float a;} r;\n" + " struct r_name {float a; float4 b;} r;\n" " column_major float3x1 t;\n" "};\n" "\n" @@ -1400,6 +1400,7 @@ static void test_reflection(void) static const D3D12_SHADER_TYPE_DESC r_field_types[] = { {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}, + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}, };
static const struct shader_variable globals_vars = @@ -1422,8 +1423,8 @@ static void test_reflection(void) {{"o", 176, 36, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_ROWS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, {{"p", 224, 16, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}, {{"q", 240, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}}, - {{"r", 256, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 1, 0, ARRAY_SIZE(r_field_types), 0, "r_name"}, r_field_types}, - {{"t", 260, 12, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, + {{"r", 256, 32, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 5, 0, ARRAY_SIZE(r_field_types), 0, "r_name"}, r_field_types}, + {{"t", 288, 12, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 3, 1, 0, 0, 0, "float3x1"}}, }; static const struct shader_variable b5_vars = {{"u", 0, 16, D3D_SVF_USED, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_VECTOR, D3D_SVT_FLOAT, 1, 4, 0, 0, 0, "float4"}}; @@ -1432,7 +1433,7 @@ static void test_reflection(void) { {{"$Globals", D3D_CT_CBUFFER, 1, 16}, &globals_vars}, {{"$Params", D3D_CT_CBUFFER, 1, 16}, ¶ms_vars}, - {{"b1", D3D_CT_CBUFFER, ARRAY_SIZE(buffer_vars), 272}, buffer_vars}, + {{"b1", D3D_CT_CBUFFER, ARRAY_SIZE(buffer_vars), 304}, buffer_vars}, {{"b5", D3D_CT_CBUFFER, 1, 16}, &b5_vars}, };
@@ -1459,11 +1460,35 @@ static void test_reflection(void) " foo = bar + 2;\n" "};\n" "sampler2D g;\n" - "sampler b : register(s5);\n" + "sampler b : register(s7);\n" + "struct\n" + "{\n" + " float a;\n" + " Texture1D<int2> b;\n" + " float c;\n" + " Texture2D d;\n" + "} h : register(t7);\n" + "struct\n" + "{\n" + " float a;\n" + " Texture2D b;\n" + " SamplerState c;\n" + "} i;\n" + "struct\n" + "{\n" + " Texture2D b;\n" + " SamplerState c;\n" + "} j;\n" + "struct\n" + "{\n" + " Texture2D a;\n" + " Texture1DArray<float> b;\n" + " struct { SamplerState a; } c;\n" + "} k;\n" "float4 main(float2 pos : texcoord) : SV_TARGET\n" "{\n" " return a.Sample(b, pos) + a.Sample(c, pos) + a.Sample(d, pos) + tex2D(f, pos) + tex2D(e, pos)" - " + tex2D(g, pos);\n" + " + tex2D(g, pos) + h.b.Load(h.c).x + k.b.Sample(k.c.a, pos);\n" "}";
static const D3D12_SHADER_INPUT_BIND_DESC ps_bindings[] = @@ -1473,11 +1498,36 @@ static void test_reflection(void) {"e", D3D_SIT_SAMPLER, 2, 1}, {"f", D3D_SIT_SAMPLER, 3, 1}, {"g", D3D_SIT_SAMPLER, 4, 1}, - {"b", D3D_SIT_SAMPLER, 5, 1, D3D_SIF_USERPACKED}, + {"k.c.a", D3D_SIT_SAMPLER, 5, 1}, + {"b", D3D_SIT_SAMPLER, 7, 1, D3D_SIF_USERPACKED}, {"f", D3D_SIT_TEXTURE, 0, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, {"e", D3D_SIT_TEXTURE, 1, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, {"g", D3D_SIT_TEXTURE, 2, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, {"a", D3D_SIT_TEXTURE, 3, 1, D3D_SIF_TEXTURE_COMPONENTS, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, ~0u}, + {"k.b", D3D_SIT_TEXTURE, 5, 1, 0, D3D_RETURN_TYPE_FLOAT, D3D_SRV_DIMENSION_TEXTURE1DARRAY, ~0u}, + {"h.b", D3D_SIT_TEXTURE, 7, 1, D3D_SIF_USERPACKED | D3D_SIF_TEXTURE_COMPONENT_0, D3D_RETURN_TYPE_SINT, D3D_SRV_DIMENSION_TEXTURE1D, ~0u}, + {"$Globals", D3D_SIT_CBUFFER, 0, 1}, + }; + + static const D3D12_SHADER_TYPE_DESC ps_h_field_types[] = + { + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}, + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}, + }; + + static const D3D12_SHADER_TYPE_DESC ps_i_field_types[] = + { + {D3D_SVC_SCALAR, D3D_SVT_FLOAT, 1, 1, 0, 0, 0, "float"}, + }; + + static const struct shader_variable ps_globals_vars[] = + { + {{"h", 0, 8, D3D_SVF_USED, NULL, 7, 1, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 4, 0, ARRAY_SIZE(ps_h_field_types), 0, "<unnamed>"}, ps_h_field_types}, + {{"i", 16, 4, 0, NULL, ~0u, 0, ~0u, 0}, {D3D_SVC_STRUCT, D3D_SVT_VOID, 1, 3, 0, ARRAY_SIZE(ps_i_field_types), 0, "<unnamed>"}, ps_i_field_types}, + }; + static const struct shader_buffer ps_buffers[] = + { + {{"$Globals", D3D_CT_CBUFFER, ARRAY_SIZE(ps_globals_vars), 32}, ps_globals_vars}, };
static const struct @@ -1492,7 +1542,7 @@ static void test_reflection(void) tests[] = { {vs_source, "vs_5_0", vs_bindings, ARRAY_SIZE(vs_bindings), vs_buffers, ARRAY_SIZE(vs_buffers)}, - {ps_source, "ps_5_0", ps_bindings, ARRAY_SIZE(ps_bindings)}, + {ps_source, "ps_5_0", ps_bindings, ARRAY_SIZE(ps_bindings), ps_buffers, ARRAY_SIZE(ps_buffers)}, };
for (unsigned int t = 0; t < ARRAY_SIZE(tests); ++t) @@ -1548,8 +1598,9 @@ static void test_reflection(void) ok(!var_desc.DefaultValue, "Got default value %p.\n", var_desc.DefaultValue); todo ok(var_desc.StartTexture == expect->var_desc.StartTexture, "Got texture offset %u.\n", var_desc.StartTexture); - ok(var_desc.TextureSize == expect->var_desc.TextureSize, - "Got texture size %u.\n", var_desc.TextureSize); + todo_if (expect->var_desc.TextureSize) + ok(var_desc.TextureSize == expect->var_desc.TextureSize, + "Got texture size %u.\n", var_desc.TextureSize); todo ok(var_desc.StartSampler == expect->var_desc.StartSampler, "Got sampler offset %u.\n", var_desc.StartSampler); ok(var_desc.SamplerSize == expect->var_desc.SamplerSize,
ERRs and char pointers fixed.
The test failure is in radv, in test_cs_uav_store(). I think that's pretty definitely unrelated. I'm not really sure I can reasonably debug it.
On Mon Mar 11 00:33:51 2024 +0000, Zebediah Figura wrote:
The test failure is in radv, in test_cs_uav_store(). I think that's pretty definitely unrelated. I'm not really sure I can reasonably debug it.
That test has been failing in the same place randomly on the CI for a while now. I've never seen it locally.
The test failure is in radv, in test_cs_uav_store(). I think that's pretty definitely unrelated. I'm not really sure I can reasonably debug it.
Given the results we're seeing (i.e., we seem to be reading back the clear value instead of the expected value from the dispatch), there's a perhaps conspicuous lack of uav_barrier() calls in test_cs_uav_store(). Is there anything in d3d12 that allows us to omit these? On the Vulkan side, UAV clears are essentially vkCmdDispatch() calls.
The test failure is in radv, in test_cs_uav_store(). I think that's pretty definitely unrelated. I'm not really sure I can reasonably debug it.
Given the results we're seeing (i.e., we seem to be reading back the clear value instead of the expected value from the dispatch), there's a perhaps conspicuous lack of uav_barrier() calls in test_cs_uav_store(). Is there anything in d3d12 that allows us to omit these? On the Vulkan side, UAV clears are essentially vkCmdDispatch() calls.
The d3d12 documentation is less than complete. It uses the language "all UAV accesses (read or writes)" when talking about UAV barriers, but then only mentions "draw or dispatch calls" specifically. It's not really clear whether clears count. Has this test ever failed on Windows? Should we just add a barrier there anyway?
The d3d12 documentation is less than complete. It uses the language "all UAV accesses (read or writes)" when talking about UAV barriers, but then only mentions "draw or dispatch calls" specifically. It's not really clear whether clears count. Has this test ever failed on Windows? Should we just add a barrier there anyway?
In dff22c9ed70811e4134c50d3d6d516b465e6a068 I ended up putting a barrier in what seems to be a similar case. My interpretation is that, absent better clarifications, it makes sense to consider clearing a write operation.
The d3d12 documentation is less than complete. It uses the language "all UAV accesses (read or writes)" when talking about UAV barriers, but then only mentions "draw or dispatch calls" specifically. It's not really clear whether clears count. Has this test ever failed on Windows? Should we just add a barrier there anyway?
Right. I guess the concrete question would be whether UAV clears imply a barrier or not. I don't think I've seen this fail on the Windows CI runs at least, but that may not be very meaningful. The CI runs these on WARP (any chance we could fix that?), which may simply not need the barriers.
For the tests, I think we should just add the barrier and see if that fixes the issue. Clears implying a barrier seems like something that would be fairly painful to debug in an actual application though; it's probably worth spending a bit of time to figure out the correct behaviour. Perhaps someone with Windows 10+ on an AMD and/or NVIDIA GPU could try running test_cs_uav_store() in a loop for a while?
For the tests, I think we should just add the barrier and see if that fixes the issue. Clears implying a barrier seems like something that would be fairly painful to debug in an actual application though; it's probably worth spending a bit of time to figure out the correct behaviour. Perhaps someone with Windows 10+ on an AMD and/or NVIDIA GPU could try running test_cs_uav_store() in a loop for a while?
I gave it a try on real AMD hardware, and I couldn't get it to trigger. However, I also couldn't get it to trigger if I replaced the UAV clear with a compute shader, and I couldn't get either one to trigger the bug on radv, even with mesa compiled to the same version that's in the tests. Attaching my best attempt for reference.
[scratch.diff](/uploads/c9244cb9679f14befd71485d7575baa8/scratch.diff)
Attaching my best attempt for reference.
That's a patch to FAudio in Wine, I'm afraid.
Attaching my best attempt for reference.
That's a patch to FAudio in Wine, I'm afraid.
Oops, wrong scratch.diff, sorry >_>
Here's the right one.
[scratch.diff](/uploads/2bea3efe1c7f8b744b73769e25c8c0ac/scratch.diff)