diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index f79f4540..76600632 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -787,13 +787,59 @@ struct vkd3d_shader_library_entry_point VkShaderStageFlagBits stage; }; -int vkd3d_shader_dxil_append_library_entry_points( +enum vkd3d_shader_subobject_kind +{ + /* Matches DXIL for simplicity. */ + VKD3D_SHADER_SUBOBJECT_KIND_STATE_OBJECT_CONFIG = 0, + VKD3D_SHADER_SUBOBJECT_KIND_GLOBAL_ROOT_SIGNATURE = 1, + VKD3D_SHADER_SUBOBJECT_KIND_LOCAL_ROOT_SIGNATURE = 2, + VKD3D_SHADER_SUBOBJECT_KIND_SUBOBJECT_TO_EXPORTS_ASSOCIATION = 8, + VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_SHADER_CONFIG = 9, + VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG = 10, + VKD3D_SHADER_SUBOBJECT_KIND_HIT_GROUP = 11, + VKD3D_SHADER_SUBOBJECT_KIND_RAYTRACING_PIPELINE_CONFIG1 = 12, +}; + +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, diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 0a3ed2cd..bfb44c01 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -1352,6 +1352,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. */ @@ -1396,20 +1421,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)); @@ -1430,6 +1530,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++) @@ -1439,24 +1541,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 @@ -1489,6 +1611,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: diff --git a/libs/vkd3d/raytracing_pipeline.c b/libs/vkd3d/raytracing_pipeline.c index 650e359e..8da85c63 100644 --- a/libs/vkd3d/raytracing_pipeline.c +++ b/libs/vkd3d/raytracing_pipeline.c @@ -371,6 +371,10 @@ struct d3d12_state_object_pipeline_data size_t entry_points_size; size_t entry_points_count; + struct vkd3d_shader_library_subobject *subobjects; + size_t subobjects_size; + size_t subobjects_count; + /* Resolve these to group + export name later. */ const struct D3D12_HIT_GROUP_DESC **hit_groups; size_t hit_groups_size; @@ -415,6 +419,7 @@ 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); @@ -563,9 +568,11 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob case D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY: { const D3D12_DXIL_LIBRARY_DESC *lib = obj->pDesc; - if (vkd3d_shader_dxil_append_library_entry_points(lib, data->dxil_libraries_count, + 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) != VKD3D_OK) + &data->entry_points_count, + &data->subobjects, &data->subobjects_size, + &data->subobjects_count) != VKD3D_OK) { ERR("Failed to parse DXIL library.\n"); return E_OUTOFMEMORY;