Compare commits

...

6 Commits

Author SHA1 Message Date
Hans-Kristian Arntzen 2851910bf5 Assign subobjects. 2 months ago
Hans-Kristian Arntzen c9c8bf8ac1 vkd3d-common: Add strequal_mixed between WCHAR and ASCII. 2 months ago
Hans-Kristian Arntzen 0ac32b5f3c Parse DXIL subobjects. 2 months ago
Hans-Kristian Arntzen df2be95553 vkd3d-shader: Forward RDAT subobjects. 2 months ago
Hans-Kristian Arntzen 090d3680f8 vkd3d: Rewrite object association. 2 months ago
Hans-Kristian Arntzen 37465ae1b5 vkd3d: Implement global root signature validation. 2 months ago
  1. 1
      include/private/vkd3d_string.h
  2. 37
      include/vkd3d_shader.h
  3. 15
      libs/vkd3d-common/string.c
  4. 171
      libs/vkd3d-shader/dxil.c
  5. 771
      libs/vkd3d/raytracing_pipeline.c

@ -30,6 +30,7 @@ WCHAR *vkd3d_dup_demangled_entry_point(const char *str);
char *vkd3d_dup_demangled_entry_point_ascii(const char *str);
bool vkd3d_export_strequal(const WCHAR *a, const WCHAR *b);
bool vkd3d_export_strequal_mixed(const WCHAR *a, const char *b);
bool vkd3d_export_strequal_substr(const WCHAR *a, size_t n, const WCHAR *b);
char *vkd3d_strdup(const char *str);

@ -794,13 +794,46 @@ enum vkd3d_shader_subobject_kind
VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1 = 12,
};
int vkd3d_shader_dxil_append_library_entry_points(
struct vkd3d_shader_library_subobject
{
enum vkd3d_shader_subobject_kind kind;
unsigned int dxil_identifier;
/* All const pointers here point directly to the DXBC blob,
* so they do not need to be freed.
* Fortunately for us, the C strings are zero-terminated in the blob itself. */
/* In the blob, ASCII is used as identifier, where API uses wide strings, sigh ... */
const char *name;
union
{
D3D12_RAYTRACING_PIPELINE_CONFIG1 pipeline_config;
D3D12_RAYTRACING_SHADER_CONFIG shader_config;
D3D12_STATE_OBJECT_CONFIG object_config;
/* Duped strings because API wants wide strings for no good reason. */
D3D12_HIT_GROUP_DESC hit_group;
D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION association;
struct
{
const void *data;
size_t size;
} payload;
} data;
};
int vkd3d_shader_dxil_append_library_entry_points_and_subobjects(
const D3D12_DXIL_LIBRARY_DESC *library_desc,
unsigned int identifier,
struct vkd3d_shader_library_entry_point **entry_points,
size_t *entry_point_size, size_t *entry_point_count);
size_t *entry_point_size, size_t *entry_point_count,
struct vkd3d_shader_library_subobject **subobjects,
size_t *subobjects_size, size_t *subobjects_count);
void vkd3d_shader_dxil_free_library_entry_points(struct vkd3d_shader_library_entry_point *entry_points, size_t count);
void vkd3d_shader_dxil_free_library_subobjects(struct vkd3d_shader_library_subobject *subobjects, size_t count);
int vkd3d_shader_compile_dxil_export(const struct vkd3d_shader_code *dxil,
const char *export,

@ -82,6 +82,21 @@ bool vkd3d_export_strequal(const WCHAR *a, const WCHAR *b)
return *a == *b;
}
bool vkd3d_export_strequal_mixed(const WCHAR *a, const char *b)
{
if (!a || !b)
return false;
while (*a != '\0' && *b != '\0')
{
if (*a != *b)
return false;
a++;
b++;
}
return *a == *b;
}
bool vkd3d_export_strequal_substr(const WCHAR *a, size_t expected_n, const WCHAR *b)
{
size_t n = 0;

@ -1316,6 +1316,31 @@ void vkd3d_shader_dxil_free_library_entry_points(struct vkd3d_shader_library_ent
vkd3d_free(entry_points);
}
void vkd3d_shader_dxil_free_library_subobjects(struct vkd3d_shader_library_subobject *subobjects, size_t count)
{
size_t i, j;
for (i = 0; i < count; i++)
{
if (subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
{
for (j = 0; j < subobjects[i].data.association.NumExports; j++)
vkd3d_free((void*)subobjects[i].data.association.pExports[j]);
vkd3d_free((void*)subobjects[i].data.association.pExports);
vkd3d_free((void*)subobjects[i].data.association.SubobjectToAssociate);
}
else if (subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_HIT_GROUP)
{
vkd3d_free((void*)subobjects[i].data.hit_group.HitGroupExport);
vkd3d_free((void*)subobjects[i].data.hit_group.AnyHitShaderImport);
vkd3d_free((void*)subobjects[i].data.hit_group.ClosestHitShaderImport);
vkd3d_free((void*)subobjects[i].data.hit_group.IntersectionShaderImport);
}
}
vkd3d_free(subobjects);
}
static VkShaderStageFlagBits convert_stage(dxil_spv_shader_stage stage)
{
/* Only interested in RT entry_points. There is no way yet to use lib_6_3+ for non-RT. */
@ -1360,20 +1385,95 @@ static bool vkd3d_dxil_build_entry(struct vkd3d_shader_library_entry_point *entr
return true;
}
int vkd3d_shader_dxil_append_library_entry_points(
static void vkd3d_shader_dxil_copy_subobject(unsigned int identifier,
struct vkd3d_shader_library_subobject *subobject,
const dxil_spv_rdat_subobject *dxil_subobject)
{
unsigned int i;
/* Reuse same enums as DXIL. */
subobject->kind = (enum vkd3d_shader_subobject_kind)dxil_subobject->kind;
subobject->name = dxil_subobject->subobject_name;
subobject->dxil_identifier = identifier;
switch (dxil_subobject->kind)
{
case DXIL_SPV_RDAT_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE:
case DXIL_SPV_RDAT_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE:
subobject->data.payload.data = dxil_subobject->payload;
subobject->data.payload.size = dxil_subobject->payload_size;
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG:
/* Normalize the kind. */
subobject->kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
subobject->data.pipeline_config.MaxTraceRecursionDepth = dxil_subobject->args[0];
subobject->data.pipeline_config.Flags = 0;
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1:
subobject->kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
subobject->data.pipeline_config.MaxTraceRecursionDepth = dxil_subobject->args[0];
subobject->data.pipeline_config.Flags = dxil_subobject->args[1];
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG:
subobject->data.shader_config.MaxPayloadSizeInBytes = dxil_subobject->args[0];
subobject->data.shader_config.MaxAttributeSizeInBytes = dxil_subobject->args[1];
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_HIT_GROUP:
/* Enum aliases. */
subobject->data.hit_group.Type = (D3D12_HIT_GROUP_TYPE)dxil_subobject->hit_group_type;
assert(dxil_subobject->num_exports == 3);
/* Implementation simplifies a lot if we can reuse the D3D12 type here. */
subobject->data.hit_group.HitGroupExport = vkd3d_dup_entry_point(dxil_subobject->subobject_name);
subobject->data.hit_group.AnyHitShaderImport = dxil_subobject->exports[0] && *dxil_subobject->exports[0] != '\0' ?
vkd3d_dup_entry_point(dxil_subobject->exports[0]) : NULL;
subobject->data.hit_group.ClosestHitShaderImport = dxil_subobject->exports[1] && *dxil_subobject->exports[1] != '\0' ?
vkd3d_dup_entry_point(dxil_subobject->exports[1]) : NULL;
subobject->data.hit_group.IntersectionShaderImport = dxil_subobject->exports[2] && *dxil_subobject->exports[2] != '\0' ?
vkd3d_dup_entry_point(dxil_subobject->exports[2]) : NULL;
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_STATE_OBJECT_CONFIG:
subobject->data.object_config.Flags = dxil_subobject->args[0];
break;
case DXIL_SPV_RDAT_SUBOBJECT_KIND_SUBOBJECT_TO_EXPORTS_ASSOCIATION:
assert(dxil_subobject->num_exports >= 1);
subobject->data.association.SubobjectToAssociate = vkd3d_dup_entry_point(dxil_subobject->exports[0]);
subobject->data.association.pExports = vkd3d_malloc((dxil_subobject->num_exports - 1) * sizeof(LPCWSTR));
subobject->data.association.NumExports = dxil_subobject->num_exports - 1;
for (i = 1; i < dxil_subobject->num_exports; i++)
subobject->data.association.pExports[i - 1] = vkd3d_dup_entry_point(dxil_subobject->exports[i]);
break;
default:
FIXME("Unrecognized RDAT subobject type: %u.\n", dxil_subobject->kind);
break;
}
}
int vkd3d_shader_dxil_append_library_entry_points_and_subobjects(
const D3D12_DXIL_LIBRARY_DESC *library_desc,
unsigned int identifier,
struct vkd3d_shader_library_entry_point **entry_points,
size_t *entry_point_size, size_t *entry_point_count)
size_t *entry_point_size, size_t *entry_point_count,
struct vkd3d_shader_library_subobject **subobjects,
size_t *subobjects_size, size_t *subobjects_count)
{
struct vkd3d_shader_library_entry_point new_entry;
struct vkd3d_shader_library_subobject *subobject;
dxil_spv_parsed_blob blob = NULL;
struct vkd3d_shader_code code;
dxil_spv_rdat_subobject sub;
dxil_spv_shader_stage stage;
const char *mangled_entry;
char *ascii_entry = NULL;
vkd3d_shader_hash_t hash;
unsigned int count, i;
unsigned int count, i, j;
unsigned int rdat_count;
int ret = VKD3D_OK;
memset(&new_entry, 0, sizeof(new_entry));
@ -1394,6 +1494,8 @@ int vkd3d_shader_dxil_append_library_entry_points(
goto end;
}
rdat_count = dxil_spv_parsed_blob_get_num_rdat_subobjects(blob);
if (library_desc->NumExports)
{
for (i = 0; i < library_desc->NumExports; i++)
@ -1403,24 +1505,44 @@ int vkd3d_shader_dxil_append_library_entry_points(
else
ascii_entry = vkd3d_strdup_w_utf8(library_desc->pExports[i].Name, 0);
stage = dxil_spv_parsed_blob_get_shader_stage_for_entry(blob, ascii_entry);
if (stage == DXIL_SPV_STAGE_UNKNOWN)
/* An export can point to a subobject or an entry point. */
for (j = 0; j < rdat_count; j++)
{
ret = VKD3D_ERROR_INVALID_ARGUMENT;
goto end;
dxil_spv_parsed_blob_get_rdat_subobject(blob, j, &sub);
/* Subobject names are not mangled. */
if (strcmp(sub.subobject_name, ascii_entry) == 0)
break;
}
new_entry.real_entry_point = ascii_entry;
new_entry.plain_entry_point = vkd3d_wstrdup(library_desc->pExports[i].Name);
new_entry.mangled_entry_point = NULL;
new_entry.identifier = identifier;
new_entry.stage = convert_stage(stage);
ascii_entry = NULL;
if (j < rdat_count)
{
vkd3d_array_reserve((void**)subobjects, subobjects_size,
*subobjects_count + 1, sizeof(**subobjects));
subobject = &(*subobjects)[*subobjects_count];
vkd3d_shader_dxil_copy_subobject(identifier, subobject, &sub);
*subobjects_count += 1;
}
else
{
stage = dxil_spv_parsed_blob_get_shader_stage_for_entry(blob, ascii_entry);
if (stage == DXIL_SPV_STAGE_UNKNOWN)
{
ret = VKD3D_ERROR_INVALID_ARGUMENT;
goto end;
}
vkd3d_array_reserve((void**)entry_points, entry_point_size,
*entry_point_count + 1, sizeof(new_entry));
(*entry_points)[(*entry_point_count)++] = new_entry;
memset(&new_entry, 0, sizeof(new_entry));
new_entry.real_entry_point = ascii_entry;
new_entry.plain_entry_point = vkd3d_wstrdup(library_desc->pExports[i].Name);
new_entry.mangled_entry_point = NULL;
new_entry.identifier = identifier;
new_entry.stage = convert_stage(stage);
ascii_entry = NULL;
vkd3d_array_reserve((void**)entry_points, entry_point_size,
*entry_point_count + 1, sizeof(new_entry));
(*entry_points)[(*entry_point_count)++] = new_entry;
memset(&new_entry, 0, sizeof(new_entry));
}
}
}
else
@ -1453,6 +1575,21 @@ int vkd3d_shader_dxil_append_library_entry_points(
(*entry_points)[(*entry_point_count)++] = new_entry;
memset(&new_entry, 0, sizeof(new_entry));
}
if (rdat_count)
{
/* All subobjects are also exported. */
vkd3d_array_reserve((void**)subobjects, subobjects_size,
*subobjects_count + rdat_count, sizeof(**subobjects));
for (i = 0; i < rdat_count; i++)
{
dxil_spv_parsed_blob_get_rdat_subobject(blob, i, &sub);
subobject = &(*subobjects)[*subobjects_count];
vkd3d_shader_dxil_copy_subobject(identifier, subobject, &sub);
*subobjects_count += 1;
}
}
}
end:

@ -366,16 +366,19 @@ struct d3d12_state_object_collection
struct d3d12_state_object_pipeline_data
{
D3D12_RAYTRACING_PIPELINE_CONFIG1 pipeline_config;
bool has_pipeline_config;
const D3D12_RAYTRACING_SHADER_CONFIG *shader_config;
/* Map 1:1 with VkShaderModule. */
struct vkd3d_shader_library_entry_point *entry_points;
size_t entry_points_size;
size_t entry_points_count;
struct vkd3d_shader_library_subobject *subobjects;
size_t subobjects_size;
size_t subobjects_count;
struct d3d12_root_signature **subobject_root_signatures;
size_t subobject_root_signatures_size;
size_t subobject_root_signatures_count;
/* Resolve these to group + export name later. */
const struct D3D12_HIT_GROUP_DESC **hit_groups;
size_t hit_groups_size;
@ -420,9 +423,14 @@ static void d3d12_state_object_pipeline_data_cleanup(struct d3d12_state_object_p
unsigned int i;
vkd3d_shader_dxil_free_library_entry_points(data->entry_points, data->entry_points_count);
vkd3d_shader_dxil_free_library_subobjects(data->subobjects, data->subobjects_count);
vkd3d_free((void*)data->hit_groups);
vkd3d_free((void*)data->dxil_libraries);
for (i = 0; i < data->subobject_root_signatures_count; i++)
d3d12_root_signature_dec_ref(data->subobject_root_signatures[i]);
vkd3d_free(data->subobject_root_signatures);
for (i = 0; i < data->exports_count; i++)
{
vkd3d_free(data->exports[i].mangled_export);
@ -442,9 +450,10 @@ static void d3d12_state_object_pipeline_data_cleanup(struct d3d12_state_object_p
#define VKD3D_ASSOCIATION_PRIORITY_INHERITED_COLLECTION 0
#define VKD3D_ASSOCIATION_PRIORITY_DXIL_SUBOBJECT 1
#define VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT 2
#define VKD3D_ASSOCIATION_PRIORITY_EXPLICIT_DEFAULT 3
#define VKD3D_ASSOCIATION_PRIORITY_EXPLICIT 4
#define VKD3D_ASSOCIATION_PRIORITY_DXIL_SUBOBJECT_ASSIGNMENT 2
#define VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT 3
#define VKD3D_ASSOCIATION_PRIORITY_EXPLICIT_DEFAULT 4
#define VKD3D_ASSOCIATION_PRIORITY_EXPLICIT 5
static HRESULT d3d12_state_object_add_collection(
struct d3d12_state_object *collection,
@ -456,41 +465,28 @@ static HRESULT d3d12_state_object_add_collection(
return E_OUTOFMEMORY;
if (!vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + 1, sizeof(*data->associations)))
data->associations_count + 3, sizeof(*data->associations)))
return E_OUTOFMEMORY;
/* If a PSO only declares collections, but no pipelines, just inherit various state.
* Also, validates that we have a match across different PSOs if we end up with mismatches. */
* Also, validates later that we have a match across different PSOs if we end up with mismatches. */
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE;
data->associations[data->associations_count].root_signature = collection->global_root_signature;
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_INHERITED_COLLECTION;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
if (data->has_pipeline_config)
{
if (memcmp(&data->pipeline_config, &collection->pipeline_config, sizeof(data->pipeline_config)) != 0)
{
FIXME("Mismatch in pipeline config state for collection and PSO.\n");
return E_INVALIDARG;
}
}
else
{
data->pipeline_config = collection->pipeline_config;
data->has_pipeline_config = true;
}
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
data->associations[data->associations_count].pipeline_config = collection->pipeline_config;
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_INHERITED_COLLECTION;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
if (data->shader_config)
{
if (memcmp(data->shader_config, &collection->shader_config, sizeof(*data->shader_config)) != 0)
{
FIXME("Mismatch in shader config state for collection and PSO.\n");
return E_INVALIDARG;
}
}
else
data->shader_config = &collection->shader_config;
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG;
data->associations[data->associations_count].shader_config = collection->shader_config;
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_INHERITED_COLLECTION;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
data->collections[data->collections_count].object = collection;
data->collections[data->collections_count].num_exports = num_exports;
@ -506,233 +502,427 @@ static HRESULT d3d12_state_object_add_collection(
return S_OK;
}
static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *object,
const D3D12_STATE_OBJECT_DESC *desc,
struct d3d12_state_object *parent,
struct d3d12_state_object_pipeline_data *data)
static void d3d12_state_object_set_association_data(struct d3d12_state_object_association *association,
const D3D12_STATE_SUBOBJECT *object)
{
unsigned int i, j;
HRESULT hr;
union
{
const D3D12_RAYTRACING_PIPELINE_CONFIG1 *pipeline_config1;
const D3D12_GLOBAL_ROOT_SIGNATURE *global_root_signature;
const D3D12_RAYTRACING_PIPELINE_CONFIG *pipeline_config;
const D3D12_LOCAL_ROOT_SIGNATURE *local_root_signature;
const D3D12_RAYTRACING_SHADER_CONFIG *shader_config;
} types;
switch (object->Type)
{
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
association->kind = VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE;
types.global_root_signature = object->pDesc;
association->root_signature =
impl_from_ID3D12RootSignature(types.global_root_signature->pGlobalRootSignature);
break;
case D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE:
association->kind = VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE;
types.local_root_signature = object->pDesc;
association->root_signature =
impl_from_ID3D12RootSignature(types.local_root_signature->pLocalRootSignature);
break;
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG:
association->kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG;
types.shader_config = object->pDesc;
association->shader_config = *types.shader_config;
break;
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1:
association->kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
types.pipeline_config1 = object->pDesc;
association->pipeline_config = *types.pipeline_config1;
break;
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG:
association->kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
types.pipeline_config = object->pDesc;
association->pipeline_config.MaxTraceRecursionDepth = types.pipeline_config->MaxTraceRecursionDepth;
association->pipeline_config.Flags = 0;
break;
if (parent && FAILED(hr = d3d12_state_object_add_collection(parent, data, NULL, 0)))
return hr;
default:
assert(0 && "Unreachable.");
break;
}
}
for (i = 0; i < desc->NumSubobjects; i++)
static HRESULT d3d12_state_object_parse_subobject(struct d3d12_state_object *object,
const D3D12_STATE_SUBOBJECT *obj,
struct d3d12_state_object_pipeline_data *data,
unsigned int association_priority)
{
unsigned int i;
HRESULT hr;
switch (obj->Type)
{
const D3D12_STATE_SUBOBJECT *obj = &desc->pSubobjects[i];
switch (obj->Type)
case D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG:
{
case D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG:
/* TODO: We might have to do global object assignment similar to SHADER_CONFIG / PIPELINE_CONFIG,
* but STATE_OBJECT_CONFIG doesn't change any functionality or compatibility rules really,
* so just append flags. */
const uint32_t supported_flags =
D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS |
D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS;
const D3D12_STATE_OBJECT_CONFIG *object_config = obj->pDesc;
object->flags |= object_config->Flags;
if (object->flags & ~supported_flags)
{
const uint32_t supported_flags =
D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS |
D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS;
const D3D12_STATE_OBJECT_CONFIG *object_config = obj->pDesc;
object->flags = object_config->Flags;
if (object->flags & ~supported_flags)
{
FIXME("Object config flag #%x is not supported.\n", object->flags);
return E_INVALIDARG;
}
break;
FIXME("Object config flag #%x is not supported.\n", object->flags);
return E_INVALIDARG;
}
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
case D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE:
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
case D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE:
{
/* LOCAL_ROOT_SIGNATURE and GLOBAL_ROOT_SIGNATURE alias. */
const D3D12_LOCAL_ROOT_SIGNATURE *rs = obj->pDesc;
/* This is only chosen as default if there is nothing else.
* Conflicting definitions seem to cause runtime to choose something
* arbitrary. Just override the low priority default.
* A high priority default association takes precedence if it exists. */
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
/* Root signatures being exported to NULL takes priority as the default local RS.
* They do however, take precedence over DXIL exported subobjects ... */
data->associations[data->associations_count].export = NULL;
data->associations[data->associations_count].kind =
obj->Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ?
VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE :
VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE;
data->associations[data->associations_count].root_signature =
impl_from_ID3D12RootSignature(rs->pLocalRootSignature);
data->associations[data->associations_count].priority = association_priority;
data->associations_count++;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY:
{
const D3D12_DXIL_LIBRARY_DESC *lib = obj->pDesc;
if (vkd3d_shader_dxil_append_library_entry_points_and_subobjects(lib, data->dxil_libraries_count,
&data->entry_points, &data->entry_points_size,
&data->entry_points_count,
&data->subobjects, &data->subobjects_size,
&data->subobjects_count) != VKD3D_OK)
{
/* LOCAL_ROOT_SIGNATURE and GLOBAL_ROOT_SIGNATURE alias. */
const D3D12_LOCAL_ROOT_SIGNATURE *rs = obj->pDesc;
/* This is only chosen as default if there is nothing else.
* Conflicting definitions seem to cause runtime to choose something
* arbitrary. Just override the low priority default.
* A high priority default association takes precedence if it exists. */
vkd3d_array_reserve((void **) &data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
/* Root signatures being exported to NULL takes priority as the default local RS.
* They do however, take precedence over DXIL exported subobjects ... */
data->associations[data->associations_count].export = NULL;
data->associations[data->associations_count].kind =
obj->Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ?
VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE :
VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE;
data->associations[data->associations_count].root_signature =
impl_from_ID3D12RootSignature(rs->pLocalRootSignature);
data->associations[data->associations_count].priority =
VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT;
data->associations_count++;
break;
ERR("Failed to parse DXIL library.\n");
return E_OUTOFMEMORY;
}
vkd3d_array_reserve((void**)&data->dxil_libraries, &data->dxil_libraries_size,
data->dxil_libraries_count + 1, sizeof(*data->dxil_libraries));
data->dxil_libraries[data->dxil_libraries_count++] = lib;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY:
case D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP:
{
const D3D12_HIT_GROUP_DESC *group = obj->pDesc;
vkd3d_array_reserve((void**)&data->hit_groups, &data->hit_groups_size,
data->hit_groups_count + 1, sizeof(*data->hit_groups));
data->hit_groups[data->hit_groups_count++] = group;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG:
{
const D3D12_RAYTRACING_SHADER_CONFIG *config = obj->pDesc;
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG;
data->associations[data->associations_count].priority = association_priority;
data->associations[data->associations_count].shader_config = *config;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG:
{
const D3D12_RAYTRACING_PIPELINE_CONFIG *pipeline_config = obj->pDesc;
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
data->associations[data->associations_count].priority = association_priority;
data->associations[data->associations_count].pipeline_config.MaxTraceRecursionDepth =
pipeline_config->MaxTraceRecursionDepth;
data->associations[data->associations_count].pipeline_config.Flags = 0;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1:
{
const D3D12_RAYTRACING_PIPELINE_CONFIG1 *pipeline_config = obj->pDesc;
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
data->associations[data->associations_count].kind = VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1;
data->associations[data->associations_count].priority = association_priority;
data->associations[data->associations_count].pipeline_config = *pipeline_config;
data->associations[data->associations_count].export = NULL;
data->associations_count++;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION:
{
const D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION *association = obj->pDesc;
unsigned int num_associations = max(association->NumExports, 1);
const struct vkd3d_shader_library_subobject *subobject;
unsigned int root_signature_index = 0;
for (i = 0; i < data->subobjects_count; i++)
{
const D3D12_DXIL_LIBRARY_DESC *lib = obj->pDesc;
if (vkd3d_shader_dxil_append_library_entry_points(lib, data->dxil_libraries_count,
&data->entry_points, &data->entry_points_size,
&data->entry_points_count) != VKD3D_OK)
if (vkd3d_export_strequal_mixed(association->SubobjectToAssociate, data->subobjects[i].name))
break;
if (data->subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE ||
data->subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE)
{
ERR("Failed to parse DXIL library.\n");
return E_OUTOFMEMORY;
root_signature_index++;
}
vkd3d_array_reserve((void**)&data->dxil_libraries, &data->dxil_libraries_size,
data->dxil_libraries_count + 1, sizeof(*data->dxil_libraries));
data->dxil_libraries[data->dxil_libraries_count++] = lib;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP:
if (i == data->subobjects_count)
{
const D3D12_HIT_GROUP_DESC *group = obj->pDesc;
vkd3d_array_reserve((void**)&data->hit_groups, &data->hit_groups_size,
data->hit_groups_count + 1, sizeof(*data->hit_groups));
data->hit_groups[data->hit_groups_count++] = group;
break;
ERR("Cannot find subobject %s.\n", debugstr_w(association->SubobjectToAssociate));
return E_INVALIDARG;
}
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG:
subobject = &data->subobjects[i];
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + num_associations,
sizeof(*data->associations));
for (i = 0; i < num_associations; i++)
{
if (data->shader_config && memcmp(data->shader_config, obj->pDesc, sizeof(*data->shader_config)) != 0)
switch (subobject->kind)
{
ERR("RAYTRACING_SHADER_CONFIG must match if multiple objects are present.\n");
return E_INVALIDARG;
}
data->shader_config = obj->pDesc;
break;
}
case VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE:
case VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE:
data->associations[data->associations_count].root_signature =
data->subobject_root_signatures[root_signature_index];
break;
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG:
{
const D3D12_RAYTRACING_PIPELINE_CONFIG *pipeline_config;
D3D12_RAYTRACING_PIPELINE_CONFIG1 config1;
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1:
data->associations[data->associations_count].pipeline_config = subobject->data.pipeline_config;
break;
pipeline_config = obj->pDesc;
config1.Flags = 0;
config1.MaxTraceRecursionDepth = pipeline_config->MaxTraceRecursionDepth;
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG:
data->associations[data->associations_count].shader_config = subobject->data.shader_config;
break;
if (data->has_pipeline_config &&
memcmp(&data->pipeline_config, &config1, sizeof(config1)) != 0)
{
ERR("RAYTRACING_PIPELINE_CONFIG must match if multiple objects are present.\n");
return E_INVALIDARG;
default:
ERR("Unexpected type %u for DXIL -> object association.\n", subobject->kind);
return E_INVALIDARG;
}
data->has_pipeline_config = true;
data->pipeline_config = config1;
break;
data->associations[data->associations_count].kind = subobject->kind;
data->associations[data->associations_count].export =
association->NumExports ? association->pExports[i] : NULL;
data->associations[data->associations_count].priority =
association_priority == VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT ?
VKD3D_ASSOCIATION_PRIORITY_EXPLICIT :
VKD3D_ASSOCIATION_PRIORITY_DXIL_SUBOBJECT_ASSIGNMENT;
data->associations_count++;
}
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1:
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION:
{
const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION *association = obj->pDesc;
unsigned int num_associations = max(association->NumExports, 1);
vkd3d_array_reserve((void **)&data->associations, &data->associations_size,
data->associations_count + num_associations,
sizeof(*data->associations));
switch (association->pSubobjectToAssociate->Type)
{
const D3D12_RAYTRACING_PIPELINE_CONFIG1 *pipeline_config = obj->pDesc;
if (data->has_pipeline_config &&
memcmp(&data->pipeline_config, pipeline_config, sizeof(*pipeline_config)) != 0)
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG:
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG:
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1:
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
case D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE:
{
ERR("RAYTRACING_PIPELINE_CONFIG1 must match if multiple objects are present.\n");
return E_INVALIDARG;
for (i = 0; i < num_associations; i++)
{
data->associations[data->associations_count].export =
association->NumExports ? association->pExports[i] : NULL;
d3d12_state_object_set_association_data(&data->associations[data->associations_count],
association->pSubobjectToAssociate);
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_EXPLICIT;
data->associations_count++;
}
break;
}
data->has_pipeline_config = true;
data->pipeline_config = *pipeline_config;
break;
default:
FIXME("Got unsupported subobject association type %u.\n", association->pSubobjectToAssociate->Type);
return E_INVALIDARG;
}
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION:
case D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION:
{
const D3D12_EXISTING_COLLECTION_DESC *collection = obj->pDesc;
struct d3d12_state_object *library_state;
library_state = impl_from_ID3D12StateObject(collection->pExistingCollection);
if (FAILED(hr = d3d12_state_object_add_collection(library_state, data,
collection->pExports, collection->NumExports)))
{
const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION *association = obj->pDesc;
return hr;
}
break;
}
/* This aliases trivially with GLOBAL_ROOT_SIGNATURE. */
const D3D12_LOCAL_ROOT_SIGNATURE *root_signature;
case D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK:
/* Just ignore this. It's irrelevant for us. */
break;
switch (association->pSubobjectToAssociate->Type)
{
/* These are irrelevant. There can only be one unique config,
* and what can happen here is that app redundantly assigns the same config.
* The associated object must be part of the PSO anyways, so it should be safe to ignore
* here. */
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG:
case D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG:
break;
default:
FIXME("Unrecognized subobject type: %u.\n", obj->Type);
return E_INVALIDARG;
}
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
case D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE:
{
root_signature = association->pSubobjectToAssociate->pDesc;
if (association->NumExports)
{
vkd3d_array_reserve((void **) &data->associations, &data->associations_size,
data->associations_count + association->NumExports,
sizeof(*data->associations));
for (j = 0; j < association->NumExports; j++)
{
data->associations[data->associations_count].export = association->pExports[j];
data->associations[data->associations_count].kind =
association->pSubobjectToAssociate->Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ?
VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE :
VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE;
data->associations[data->associations_count].root_signature =
impl_from_ID3D12RootSignature(root_signature->pLocalRootSignature);
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_EXPLICIT;
data->associations_count++;
}
}
else
{
vkd3d_array_reserve((void **) &data->associations, &data->associations_size,
data->associations_count + 1,
sizeof(*data->associations));
/* Local root signatures being exported to NULL takes priority as the default local RS. */
data->associations[data->associations_count].export = NULL;
data->associations[data->associations_count].kind =
association->pSubobjectToAssociate->Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ?
VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE :
VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE;
data->associations[data->associations_count].root_signature =
impl_from_ID3D12RootSignature(root_signature->pLocalRootSignature);
data->associations[data->associations_count].priority = VKD3D_ASSOCIATION_PRIORITY_EXPLICIT_DEFAULT;
data->associations_count++;
}
break;
}
return S_OK;
}
default:
FIXME("Got unsupported subobject association type %u.\n", association->pSubobjectToAssociate->Type);
return E_INVALIDARG;
}
static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *object,
const D3D12_STATE_OBJECT_DESC *desc,
struct d3d12_state_object *parent,
struct d3d12_state_object_pipeline_data *data)
{
struct d3d12_root_signature *root_signature;
unsigned int i;
HRESULT hr;
if (parent && FAILED(hr = d3d12_state_object_add_collection(parent, data, NULL, 0)))
return hr;
/* Make sure all state has been parsed. Ignore DXIL subobject associations for now. We'll have to parse subobjects
* first. */
for (i = 0; i < desc->NumSubobjects; i++)
{
const D3D12_STATE_SUBOBJECT *obj = &desc->pSubobjects[i];
if (obj->Type != D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION &&
obj->Type != D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK)
{
if (FAILED(hr = d3d12_state_object_parse_subobject(object, obj, data,
VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT)))
return hr;
}
}
/* Make sure all child state has been parsed. */
for (i = 0; i < data->subobjects_count; i++)
{
D3D12_GLOBAL_ROOT_SIGNATURE obj_root_signature;
D3D12_STATE_SUBOBJECT obj;
obj.pDesc = NULL;
switch (data->subobjects[i].kind)
{
case VKD3D_SHADER_SUBOBJECT_KIND_STATE_OBJECT_CONFIG:
obj.Type = D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;
obj.pDesc = &data->subobjects[i].data.object_config;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION:
{
const D3D12_EXISTING_COLLECTION_DESC *collection = obj->pDesc;
struct d3d12_state_object *library_state;
library_state = impl_from_ID3D12StateObject(collection->pExistingCollection);
if (FAILED(hr = d3d12_state_object_add_collection(library_state, data,
collection->pExports, collection->NumExports)))
{
return hr;
}
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG:
obj.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
obj.pDesc = &data->subobjects[i].data.shader_config;
break;
}
case D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK:
/* Just ignore this. It's irrelevant for us. */
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1:
obj.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1;
obj.pDesc = &data->subobjects[i].data.pipeline_config;
break;
case VKD3D_SHADER_SUBOBJECT_KIND_HIT_GROUP:
obj.Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
obj.pDesc = &data->subobjects[i].data.hit_group;
break;
case VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE:
case VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE:
if (FAILED(hr = d3d12_root_signature_create(object->device, data->subobjects[i].data.payload.data,
data->subobjects[i].data.payload.size, &root_signature)))
return hr;
d3d12_root_signature_inc_ref(root_signature);
ID3D12RootSignature_Release(&root_signature->ID3D12RootSignature_iface);
obj_root_signature.pGlobalRootSignature = &root_signature->ID3D12RootSignature_iface;
obj.Type = data->subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE ?
D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE : D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;
obj.pDesc = &obj_root_signature;
vkd3d_array_reserve((void**)&data->subobject_root_signatures, &data->subobject_root_signatures_size,
data->subobject_root_signatures_count + 1, sizeof(*data->subobject_root_signatures));
data->subobject_root_signatures[data->subobject_root_signatures_count++] = root_signature;
break;
default:
FIXME("Unrecognized subobject type: %u.\n", obj->Type);
return E_INVALIDARG;
break;
}
if (obj.pDesc && FAILED(hr = d3d12_state_object_parse_subobject(
object, &obj, data, VKD3D_ASSOCIATION_PRIORITY_DXIL_SUBOBJECT)))
return hr;
}
if (!data->has_pipeline_config)
for (i = 0; i < desc->NumSubobjects; i++)
{
ERR("Must have pipeline config.\n");
return E_INVALIDARG;
const D3D12_STATE_SUBOBJECT *obj = &desc->pSubobjects[i];
/* Now we can parse DXIL subobject -> export associations. */
if (obj->Type == D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
{
if (FAILED(hr = d3d12_state_object_parse_subobject(object, obj, data,
VKD3D_ASSOCIATION_PRIORITY_DECLARED_STATE_OBJECT)))
return hr;
}
}
if (!data->shader_config)
/* Finally, parse subobject version of DXIL subobject to export. */
for (i = 0; i < data->subobjects_count; i++)
{
ERR("Must have shader config.\n");
return E_INVALIDARG;
if (data->subobjects[i].kind == VKD3D_SHADER_SUBOBJECT_KIND_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
{
D3D12_STATE_SUBOBJECT obj;
obj.Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
obj.pDesc = &data->subobjects[i].data.association;
if (FAILED(hr = d3d12_state_object_parse_subobject(object, &obj, data,
VKD3D_ASSOCIATION_PRIORITY_DXIL_SUBOBJECT)))
return hr;
}
}
return S_OK;
@ -897,6 +1087,33 @@ static VkDeviceSize d3d12_state_object_pipeline_data_compute_default_stack_size(
return pipeline_stack_size;
}
static bool d3d12_state_object_association_data_equal(const struct d3d12_state_object_association *a,
const struct d3d12_state_object_association *b)
{
if (a->kind != b->kind)
return false;
switch (a->kind)
{
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1:
return memcmp(&a->pipeline_config, &b->pipeline_config, sizeof(a->pipeline_config)) == 0;
case VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG:
return memcmp(&a->shader_config, &b->shader_config, sizeof(a->shader_config)) == 0;
case VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE:
case VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE:
if (!a->root_signature && !b->root_signature)
return true;
if ((!!a->root_signature) != (!!b->root_signature))
return false;
return a->root_signature->compatibility_hash == b->root_signature->compatibility_hash;
default:
break;
}
return false;
}
static struct d3d12_state_object_association *d3d12_state_object_find_association(
enum vkd3d_shader_subobject_kind kind,
struct d3d12_state_object_pipeline_data *data,
@ -904,6 +1121,7 @@ static struct d3d12_state_object_association *d3d12_state_object_find_associatio
LPCWSTR export)
{
struct d3d12_state_object_association *association = NULL;
bool conflict = false;
bool match;
size_t i;
@ -917,9 +1135,9 @@ static struct d3d12_state_object_association *d3d12_state_object_find_associatio
if (data->associations[i].export)
{
if (entry)
vkd3d_export_equal(data->associations[i].export, entry);
match = vkd3d_export_equal(data->associations[i].export, entry);
else
vkd3d_export_strequal(data->associations[i].export, export);
match = vkd3d_export_strequal(data->associations[i].export, export);
}
else
match = true;
@ -929,16 +1147,22 @@ static struct d3d12_state_object_association *d3d12_state_object_find_associatio
if (!association || data->associations[i].priority > association->priority)
{
association = &data->associations[i];
conflict = false;
}
else if (association->root_signature->compatibility_hash !=
data->associations[i].root_signature->compatibility_hash)
else if (!d3d12_state_object_association_data_equal(association, &data->associations[i]))
{
ERR("Conflicting root signatures defined for same export.\n");
return NULL;
/* We might get a higher priority match later that makes this conflict irrelevant. */
conflict = true;
}
}
}
if (conflict)
{
ERR("Conflicting root signatures defined for same export.\n");
return NULL;
}
return association;
}
@ -953,6 +1177,7 @@ static struct d3d12_root_signature *d3d12_state_object_pipeline_data_get_root_si
size_t i;
direct_association = d3d12_state_object_find_association(kind, data, entry, NULL);
hit_group_association = NULL;
/* If we didn't find an association for this entry point, we might have an association
* in a hit group export.
@ -975,7 +1200,7 @@ static struct d3d12_root_signature *d3d12_state_object_pipeline_data_get_root_si
if (!direct_association || hit_group_association->priority > direct_association->priority)
direct_association = hit_group_association;
return direct_association->root_signature;
return direct_association ? direct_association->root_signature : NULL;
}
static HRESULT d3d12_state_object_get_group_handles(struct d3d12_state_object *object,
@ -1110,17 +1335,97 @@ static void d3d12_state_object_append_local_static_samplers(
*out_vk_bindings_count = vk_bindings_count;
}
static struct d3d12_root_signature *d3d12_state_object_pipeline_data_find_global_root_signature(
struct d3d12_state_object_pipeline_data *data)
static bool d3d12_state_object_pipeline_data_find_global_state_object(
struct d3d12_state_object_pipeline_data *data,
enum vkd3d_shader_subobject_kind kind,
const struct d3d12_state_object_association **out_association)
{
const struct d3d12_state_object_association *association = NULL;
const struct d3d12_state_object_association *candidate;
size_t i;
/* All inherited associations have to agree. */
for (i = 0; i < data->associations_count; i++)
{
if (data->associations[i].kind == kind &&
data->associations[i].priority == VKD3D_ASSOCIATION_PRIORITY_INHERITED_COLLECTION)
{
if (!association)
association = &data->associations[i];
else if (!d3d12_state_object_association_data_equal(association, &data->associations[i]))
{
ERR("Mismatch in inherited associations for kind %u.\n", kind);
return false;
}
}
}
for (i = 0; i < data->entry_points_count; i++)
{
candidate = d3d12_state_object_find_association(kind, data,
&data->entry_points[i], NULL);
if (!association)
{
association = candidate;
}
else if (!d3d12_state_object_association_data_equal(association, candidate))
{
/* To hypothetically support this for global root signatures,
* we'd have to partition any RTPSO into N VkPipelines and select
* the appropriate pipeline at DispatchRays() time based on the currently bound root signature ...
* Leave this as a TODO until we observe that applications rely on this esoteric behavior. */
if (kind == VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE)
FIXME("Two entry points declare different global root signatures. This is currently unsupported.\n");
else
ERR("Mismatch in inherited associations for kind %u.\n", kind);
return false;
}
}
*out_association = association;
return true;
}
static bool d3d12_state_object_pipeline_data_validate_global_root_signature(
struct d3d12_state_object_pipeline_data *data,
struct d3d12_root_signature *global_signature)
static bool d3d12_state_object_pipeline_data_find_global_state_objects(
struct d3d12_state_object_pipeline_data *data, struct d3d12_root_signature **out_root_signature,
D3D12_RAYTRACING_SHADER_CONFIG *out_shader_config,
D3D12_RAYTRACING_PIPELINE_CONFIG1 *out_pipeline_config)
{
const struct d3d12_state_object_association *pipeline_config = NULL;
const struct d3d12_state_object_association *root_signature = NULL;
const struct d3d12_state_object_association *shader_config = NULL;
if (!d3d12_state_object_pipeline_data_find_global_state_object(data,
VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE, &root_signature))
return false;
if (!d3d12_state_object_pipeline_data_find_global_state_object(data,
VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1, &pipeline_config))
return false;
if (!d3d12_state_object_pipeline_data_find_global_state_object(data,
VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG, &shader_config))
return false;
if (!pipeline_config)
{
ERR("No pipeline config was declared or inherited. This is required state.\n");
return false;
}
if (!shader_config)
{
ERR("No shader config was declared or inherited. This is required state.\n");
return false;
}
/* If every entry point declares no root signature, this is still okay. */
*out_root_signature = root_signature ? root_signature->root_signature : NULL;
*out_pipeline_config = pipeline_config->pipeline_config;
*out_shader_config = shader_config->shader_config;
return true;
}
static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *object,
@ -1135,11 +1440,13 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
VkRayTracingPipelineCreateInfoKH