Compare commits
7 Commits
master
...
further-rt
Author | SHA1 | Date |
---|---|---|
Hans-Kristian Arntzen | b817f972f4 | |
Hans-Kristian Arntzen | b9c575d678 | |
Hans-Kristian Arntzen | ab85bdf94f | |
Hans-Kristian Arntzen | 3d1b2d2042 | |
Hans-Kristian Arntzen | ccf927da7f | |
Hans-Kristian Arntzen | c940d548f4 | |
Hans-Kristian Arntzen | 53309d05a1 |
|
@ -4889,7 +4889,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateStateObject(d3d12_device_ifa
|
|||
TRACE("iface %p, desc %p, iid %s, state_object %p!\n",
|
||||
iface, desc, debugstr_guid(iid), state_object);
|
||||
|
||||
if (FAILED(hr = d3d12_state_object_create(device, desc, &state)))
|
||||
if (FAILED(hr = d3d12_state_object_create(device, desc, NULL, &state)))
|
||||
return hr;
|
||||
|
||||
return return_interface(&state->ID3D12StateObject_iface, &IID_ID3D12StateObject, iid, state_object);
|
||||
|
@ -4957,13 +4957,23 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetBackgroundProcessingMode(d3d12_
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE d3d12_device_AddToStateObject(d3d12_device_iface *iface, const D3D12_STATE_OBJECT_DESC *addition,
|
||||
ID3D12StateObject *state_object, REFIID riid, void **new_state_object)
|
||||
static HRESULT STDMETHODCALLTYPE d3d12_device_AddToStateObject(d3d12_device_iface *iface,
|
||||
const D3D12_STATE_OBJECT_DESC *addition,
|
||||
ID3D12StateObject *parent_state, REFIID riid, void **new_state_object)
|
||||
{
|
||||
FIXME("iface %p, addition %p, state_object %p, riid %s, new_state_object %p stub!\n",
|
||||
iface, addition, state_object, debugstr_guid(riid), new_state_object);
|
||||
struct d3d12_device *device = impl_from_ID3D12Device(iface);
|
||||
struct d3d12_state_object *parent;
|
||||
struct d3d12_state_object *state;
|
||||
HRESULT hr;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("iface %p, addition %p, state_object %p, riid %s, new_state_object %p stub!\n",
|
||||
iface, addition, parent_state, debugstr_guid(riid), new_state_object);
|
||||
|
||||
parent = impl_from_ID3D12StateObject(parent_state);
|
||||
if (FAILED(hr = d3d12_state_object_add(device, addition, parent, &state)))
|
||||
return hr;
|
||||
|
||||
return return_interface(&state->ID3D12StateObject_iface, &IID_ID3D12StateObject, riid, new_state_object);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE d3d12_device_CreateProtectedResourceSession1(d3d12_device_iface *iface,
|
||||
|
|
|
@ -122,7 +122,11 @@ static void d3d12_state_object_cleanup(struct d3d12_state_object *object)
|
|||
d3d12_state_object_dec_ref(object->collections[i]);
|
||||
vkd3d_free(object->collections);
|
||||
|
||||
if (object->global_root_signature)
|
||||
d3d12_root_signature_dec_ref(object->global_root_signature);
|
||||
|
||||
VK_CALL(vkDestroyPipeline(object->device->vk_device, object->pipeline, NULL));
|
||||
VK_CALL(vkDestroyPipeline(object->device->vk_device, object->pipeline_library, NULL));
|
||||
|
||||
VK_CALL(vkDestroyPipelineLayout(object->device->vk_device,
|
||||
object->local_static_sampler.pipeline_layout, NULL));
|
||||
|
@ -237,6 +241,7 @@ static void * STDMETHODCALLTYPE d3d12_state_object_properties_GetShaderIdentifie
|
|||
LPCWSTR export_name)
|
||||
{
|
||||
struct d3d12_state_object *object = impl_from_ID3D12StateObjectProperties(iface);
|
||||
struct d3d12_state_object_identifier *export;
|
||||
const WCHAR *subtype = NULL;
|
||||
uint32_t index;
|
||||
|
||||
|
@ -247,7 +252,14 @@ static void * STDMETHODCALLTYPE d3d12_state_object_properties_GetShaderIdentifie
|
|||
/* Cannot query shader identifier for non-group names. */
|
||||
if (!subtype && index != UINT32_MAX)
|
||||
{
|
||||
return object->exports[index].identifier;
|
||||
export = &object->exports[index];
|
||||
/* Need to return the parent SBT pointer if it exists */
|
||||
while (export->inherited_collection_index >= 0)
|
||||
{
|
||||
object = object->collections[export->inherited_collection_index];
|
||||
export = &object->exports[export->inherited_collection_export_index];
|
||||
}
|
||||
return export->identifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -350,9 +362,9 @@ struct d3d12_state_object_pipeline_data
|
|||
bool has_pipeline_config;
|
||||
|
||||
const D3D12_RAYTRACING_SHADER_CONFIG *shader_config;
|
||||
ID3D12RootSignature *global_root_signature;
|
||||
ID3D12RootSignature *high_priority_local_root_signature;
|
||||
ID3D12RootSignature *low_priority_local_root_signature;
|
||||
struct d3d12_root_signature *global_root_signature;
|
||||
struct d3d12_root_signature *high_priority_local_root_signature;
|
||||
struct d3d12_root_signature *low_priority_local_root_signature;
|
||||
|
||||
/* Map 1:1 with VkShaderModule. */
|
||||
struct vkd3d_shader_library_entry_point *entry_points;
|
||||
|
@ -423,10 +435,78 @@ static void d3d12_state_object_pipeline_data_cleanup(struct d3d12_state_object_p
|
|||
vkd3d_free(data->vk_libraries);
|
||||
}
|
||||
|
||||
static HRESULT d3d12_state_object_add_collection(
|
||||
struct d3d12_state_object *collection,
|
||||
struct d3d12_state_object_pipeline_data *data,
|
||||
const D3D12_EXPORT_DESC *exports, unsigned int num_exports)
|
||||
{
|
||||
if (!vkd3d_array_reserve((void **)&data->collections, &data->collections_size,
|
||||
data->collections_count + 1, sizeof(*data->collections)))
|
||||
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 (data->global_root_signature)
|
||||
{
|
||||
if (!collection->global_root_signature ||
|
||||
data->global_root_signature->compatibility_hash != collection->global_root_signature->compatibility_hash)
|
||||
{
|
||||
FIXME("Mismatch in global root signature state for PSO and collection.\n");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
data->global_root_signature = collection->global_root_signature;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->collections[data->collections_count].object = collection;
|
||||
data->collections[data->collections_count].num_exports = num_exports;
|
||||
data->collections[data->collections_count].exports = exports;
|
||||
|
||||
vkd3d_array_reserve((void **)&data->vk_libraries, &data->vk_libraries_size,
|
||||
data->vk_libraries_count + 1, sizeof(*data->vk_libraries));
|
||||
data->vk_libraries[data->vk_libraries_count] =
|
||||
data->collections[data->collections_count].object->pipeline_library;
|
||||
|
||||
data->collections_count += 1;
|
||||
data->vk_libraries_count += 1;
|
||||
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_pipeline_data *data)
|
||||
const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent,
|
||||
struct d3d12_state_object_pipeline_data *data)
|
||||
{
|
||||
unsigned int i, j;
|
||||
HRESULT hr;
|
||||
|
||||
if (parent && FAILED(hr = d3d12_state_object_add_collection(parent, data, NULL, 0)))
|
||||
return hr;
|
||||
|
||||
for (i = 0; i < desc->NumSubobjects; i++)
|
||||
{
|
||||
|
@ -435,9 +515,12 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob
|
|||
{
|
||||
case D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG:
|
||||
{
|
||||
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 & ~D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS)
|
||||
if (object->flags & ~supported_flags)
|
||||
{
|
||||
FIXME("Object config flag #%x is not supported.\n", object->flags);
|
||||
return E_INVALIDARG;
|
||||
|
@ -448,13 +531,21 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob
|
|||
case D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE:
|
||||
{
|
||||
const D3D12_GLOBAL_ROOT_SIGNATURE *rs = obj->pDesc;
|
||||
if (data->global_root_signature)
|
||||
struct d3d12_root_signature *new_rs;
|
||||
struct d3d12_root_signature *old_rs;
|
||||
|
||||
new_rs = impl_from_ID3D12RootSignature(rs->pGlobalRootSignature);
|
||||
old_rs = data->global_root_signature;
|
||||
|
||||
if (new_rs && old_rs && new_rs->compatibility_hash != old_rs->compatibility_hash)
|
||||
{
|
||||
/* Simplicity for now. */
|
||||
FIXME("More than one global root signature is used.\n");
|
||||
FIXME("More than one unique global root signature is used.\n");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
data->global_root_signature = rs->pGlobalRootSignature;
|
||||
|
||||
if (!data->global_root_signature)
|
||||
data->global_root_signature = new_rs;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -465,7 +556,7 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob
|
|||
* 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. */
|
||||
data->low_priority_local_root_signature = rs->pLocalRootSignature;
|
||||
data->low_priority_local_root_signature = impl_from_ID3D12RootSignature(rs->pLocalRootSignature);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -574,7 +665,8 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob
|
|||
else
|
||||
{
|
||||
/* Local root signatures being exported to NULL takes priority as the default local RS. */
|
||||
data->high_priority_local_root_signature = local_rs->pLocalRootSignature;
|
||||
data->high_priority_local_root_signature =
|
||||
impl_from_ID3D12RootSignature(local_rs->pLocalRootSignature);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -589,22 +681,20 @@ static HRESULT d3d12_state_object_parse_subobjects(struct d3d12_state_object *ob
|
|||
case D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION:
|
||||
{
|
||||
const D3D12_EXISTING_COLLECTION_DESC *collection = obj->pDesc;
|
||||
vkd3d_array_reserve((void **)&data->collections, &data->collections_size,
|
||||
data->collections_count + 1, sizeof(*data->collections));
|
||||
|
||||
data->collections[data->collections_count].object = impl_from_ID3D12StateObject(collection->pExistingCollection);
|
||||
data->collections[data->collections_count].num_exports = collection->NumExports;
|
||||
data->collections[data->collections_count].exports = collection->pExports;
|
||||
|
||||
vkd3d_array_reserve((void **)&data->vk_libraries, &data->vk_libraries_size,
|
||||
data->vk_libraries_count + 1, sizeof(*data->vk_libraries));
|
||||
data->vk_libraries[data->vk_libraries_count] = data->collections[data->collections_count].object->pipeline;
|
||||
|
||||
data->collections_count += 1;
|
||||
data->vk_libraries_count += 1;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK:
|
||||
/* Just ignore this. It's irrelevant for us. */
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Unrecognized subobject type: %u.\n", obj->Type);
|
||||
return E_INVALIDARG;
|
||||
|
@ -660,7 +750,8 @@ static uint32_t d3d12_state_object_pipeline_data_find_entry(
|
|||
|
||||
offset += data->stages_count;
|
||||
|
||||
/* Try to look in collections. */
|
||||
/* Try to look in collections. We'll only find something in the ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL
|
||||
* situation. Otherwise entry_points will be NULL. */
|
||||
for (i = 0; i < data->collections_count; i++)
|
||||
{
|
||||
index = d3d12_state_object_pipeline_data_find_entry_inner(data->collections[i].object->entry_points,
|
||||
|
@ -833,9 +924,9 @@ static struct d3d12_root_signature *d3d12_state_object_pipeline_data_get_local_r
|
|||
if (!rs)
|
||||
{
|
||||
if (data->high_priority_local_root_signature)
|
||||
rs = impl_from_ID3D12RootSignature(data->high_priority_local_root_signature);
|
||||
rs = data->high_priority_local_root_signature;
|
||||
else if (data->low_priority_local_root_signature)
|
||||
rs = impl_from_ID3D12RootSignature(data->low_priority_local_root_signature);
|
||||
rs = data->low_priority_local_root_signature;
|
||||
else
|
||||
rs = NULL;
|
||||
}
|
||||
|
@ -847,6 +938,8 @@ static HRESULT d3d12_state_object_get_group_handles(struct d3d12_state_object *o
|
|||
const struct d3d12_state_object_pipeline_data *data)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &object->device->vk_procs;
|
||||
uint32_t collection_export;
|
||||
int collection_index;
|
||||
uint32_t group_index;
|
||||
VkResult vr;
|
||||
size_t i;
|
||||
|
@ -862,6 +955,27 @@ static HRESULT d3d12_state_object_get_group_handles(struct d3d12_state_object *o
|
|||
if (vr)
|
||||
return hresult_from_vk_result(vr);
|
||||
|
||||
collection_export = data->exports[i].inherited_collection_export_index;
|
||||
collection_index = data->exports[i].inherited_collection_index;
|
||||
|
||||
if (collection_index >= 0)
|
||||
{
|
||||
const uint8_t *parent_identifier;
|
||||
const uint8_t *child_identifier;
|
||||
|
||||
parent_identifier = data->collections[collection_index].object->exports[collection_export].identifier;
|
||||
child_identifier = data->exports[i].identifier;
|
||||
|
||||
/* Validate that we get an exact match for SBT handle.
|
||||
* It appears to work just fine on NV. */
|
||||
if (memcmp(parent_identifier, child_identifier, D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES) != 0)
|
||||
{
|
||||
FIXME("SBT identifiers do not match for parent and child pipelines. "
|
||||
"Vulkan does not guarantee this, but DXR 1.1 requires this. Cannot use pipeline.\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
data->exports[i].stack_size_general = UINT32_MAX;
|
||||
data->exports[i].stack_size_any = UINT32_MAX;
|
||||
data->exports[i].stack_size_closest = UINT32_MAX;
|
||||
|
@ -998,7 +1112,7 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
shader_interface_info.stage = VK_SHADER_STAGE_ALL;
|
||||
shader_interface_info.xfb_info = NULL;
|
||||
|
||||
global_signature = impl_from_ID3D12RootSignature(data->global_root_signature);
|
||||
global_signature = data->global_root_signature;
|
||||
|
||||
if (global_signature)
|
||||
{
|
||||
|
@ -1083,6 +1197,8 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
export->closest_stage_index = VK_SHADER_UNUSED_KHR;
|
||||
export->anyhit_stage_index = VK_SHADER_UNUSED_KHR;
|
||||
export->intersection_stage_index = VK_SHADER_UNUSED_KHR;
|
||||
export->inherited_collection_index = -1;
|
||||
export->inherited_collection_export_index = 0;
|
||||
export->general_stage = entry->stage;
|
||||
entry->mangled_entry_point = NULL;
|
||||
entry->plain_entry_point = NULL;
|
||||
|
@ -1182,6 +1298,8 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR,
|
||||
export);
|
||||
|
||||
export->inherited_collection_index = -1;
|
||||
export->inherited_collection_export_index = 0;
|
||||
data->exports_count += 1;
|
||||
data->groups_count += 1;
|
||||
}
|
||||
|
@ -1264,6 +1382,16 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
if (export->intersection_stage_index != VK_SHADER_UNUSED_KHR)
|
||||
export->intersection_stage_index += pstage_offset;
|
||||
|
||||
/* If we inherited from a real pipeline, we must observe the rules of AddToStateObject().
|
||||
* SBT pointer must be invariant as well as its contents.
|
||||
* Vulkan does not guarantee this, but we can validate and accept the pipeline if
|
||||
* implementation happens to satisfy this rule. */
|
||||
if (collection->object->type == D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE)
|
||||
export->inherited_collection_index = (int)i;
|
||||
else
|
||||
export->inherited_collection_index = -1;
|
||||
export->inherited_collection_export_index = input_export->group_index;
|
||||
|
||||
data->exports_count += 1;
|
||||
}
|
||||
|
||||
|
@ -1303,7 +1431,12 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
|
||||
pipeline_create_info.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
|
||||
pipeline_create_info.pNext = NULL;
|
||||
pipeline_create_info.flags = object->type == D3D12_STATE_OBJECT_TYPE_COLLECTION ?
|
||||
|
||||
/* If we allow state object additions, we must first lower this pipeline to a library, and
|
||||
* then link it to itself so we can use it a library in subsequent PSO creations, but we
|
||||
* must also be able to trace rays from the library. */
|
||||
pipeline_create_info.flags = (object->type == D3D12_STATE_OBJECT_TYPE_COLLECTION ||
|
||||
(object->flags & D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS)) ?
|
||||
VK_PIPELINE_CREATE_LIBRARY_BIT_KHR : 0;
|
||||
|
||||
/* FIXME: What if we have no global root signature? */
|
||||
|
@ -1363,7 +1496,27 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
dynamic_state.pDynamicStates = dynamic_states;
|
||||
|
||||
vr = VK_CALL(vkCreateRayTracingPipelinesKHR(object->device->vk_device, VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE, 1, &pipeline_create_info, NULL, &object->pipeline));
|
||||
VK_NULL_HANDLE, 1, &pipeline_create_info, NULL,
|
||||
(pipeline_create_info.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) ?
|
||||
&object->pipeline_library : &object->pipeline));
|
||||
|
||||
if (vr == VK_SUCCESS && (object->flags & D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS) &&
|
||||
object->type == D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE)
|
||||
{
|
||||
/* TODO: Is it actually valid to inherit other pipeline libraries while creating a pipeline library? */
|
||||
pipeline_create_info.flags &= ~VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
|
||||
pipeline_create_info.pStages = NULL;
|
||||
pipeline_create_info.pGroups = NULL;
|
||||
pipeline_create_info.stageCount = 0;
|
||||
pipeline_create_info.groupCount = 0;
|
||||
library_info.libraryCount = 1;
|
||||
library_info.pLibraries = &object->pipeline_library;
|
||||
|
||||
/* Self-link the pipeline library. */
|
||||
vr = VK_CALL(vkCreateRayTracingPipelinesKHR(object->device->vk_device, VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE, 1, &pipeline_create_info, NULL, &object->pipeline));
|
||||
}
|
||||
|
||||
if (vr)
|
||||
return hresult_from_vk_result(vr);
|
||||
|
||||
|
@ -1387,6 +1540,11 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
data->exports_size = 0;
|
||||
data->exports_count = 0;
|
||||
|
||||
d3d12_root_signature_inc_ref(object->global_root_signature = global_signature);
|
||||
|
||||
object->shader_config = *data->shader_config;
|
||||
object->pipeline_config = data->pipeline_config;
|
||||
|
||||
/* Spec says we need to hold a reference to the collection object, but it doesn't show up in API,
|
||||
* so we must assume private reference. */
|
||||
if (data->collections_count)
|
||||
|
@ -1417,7 +1575,8 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob
|
|||
|
||||
static HRESULT d3d12_state_object_init(struct d3d12_state_object *object,
|
||||
struct d3d12_device *device,
|
||||
const D3D12_STATE_OBJECT_DESC *desc)
|
||||
const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent)
|
||||
{
|
||||
struct d3d12_state_object_pipeline_data data;
|
||||
HRESULT hr = S_OK;
|
||||
|
@ -1429,7 +1588,7 @@ static HRESULT d3d12_state_object_init(struct d3d12_state_object *object,
|
|||
object->type = desc->Type;
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
if (FAILED(hr = d3d12_state_object_parse_subobjects(object, desc, &data)))
|
||||
if (FAILED(hr = d3d12_state_object_parse_subobjects(object, desc, parent, &data)))
|
||||
goto fail;
|
||||
|
||||
if (FAILED(hr = d3d12_state_object_compile_pipeline(object, &data)))
|
||||
|
@ -1449,6 +1608,7 @@ fail:
|
|||
}
|
||||
|
||||
HRESULT d3d12_state_object_create(struct d3d12_device *device, const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent,
|
||||
struct d3d12_state_object **state_object)
|
||||
{
|
||||
struct d3d12_state_object *object;
|
||||
|
@ -1457,7 +1617,7 @@ HRESULT d3d12_state_object_create(struct d3d12_device *device, const D3D12_STATE
|
|||
if (!(object = vkd3d_calloc(1, sizeof(*object))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hr = d3d12_state_object_init(object, device, desc);
|
||||
hr = d3d12_state_object_init(object, device, desc, parent);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
vkd3d_free(object);
|
||||
|
@ -1467,3 +1627,34 @@ HRESULT d3d12_state_object_create(struct d3d12_device *device, const D3D12_STATE
|
|||
*state_object = object;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT d3d12_state_object_add(struct d3d12_device *device, const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent, struct d3d12_state_object **state_object)
|
||||
{
|
||||
unsigned int i;
|
||||
HRESULT hr;
|
||||
|
||||
if (!parent)
|
||||
return E_INVALIDARG;
|
||||
if (!(parent->flags & D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS))
|
||||
return E_INVALIDARG;
|
||||
if (desc->Type != D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE)
|
||||
return E_INVALIDARG;
|
||||
|
||||
/* Addition must also allow this scenario. */
|
||||
for (i = 0; i < desc->NumSubobjects; i++)
|
||||
{
|
||||
if (desc->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG)
|
||||
{
|
||||
const D3D12_STATE_OBJECT_CONFIG *config = desc->pSubobjects[i].pDesc;
|
||||
if (config->Flags & D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == desc->NumSubobjects)
|
||||
return E_INVALIDARG;
|
||||
|
||||
hr = d3d12_state_object_create(device, desc, parent, state_object);
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -3374,6 +3374,14 @@ struct d3d12_state_object_identifier
|
|||
|
||||
/* The index into vkGetShaderStackSize and friends for pGroups[]. */
|
||||
uint32_t group_index;
|
||||
|
||||
/* For AddToStateObject(). We need to return the identifier pointer
|
||||
* for the parent, not the child. This makes it easy to validate that
|
||||
* we observe the same SBT handles as specified by DXR 1.1. */
|
||||
|
||||
/* If -1, ignore, otherwise, redirect. */
|
||||
int inherited_collection_index;
|
||||
uint32_t inherited_collection_export_index;
|
||||
};
|
||||
|
||||
struct d3d12_state_object_stack_info
|
||||
|
@ -3407,7 +3415,14 @@ struct d3d12_state_object
|
|||
/* Normally stages_count == entry_points_count, but entry_points is the entry points we
|
||||
* export externally, and stages_count matches pStages[] size for purposes of index fixups. */
|
||||
|
||||
/* Can be bound. */
|
||||
VkPipeline pipeline;
|
||||
/* Can be used as a library. */
|
||||
VkPipeline pipeline_library;
|
||||
|
||||
/* Can be inherited by AddToStateObject(). */
|
||||
D3D12_RAYTRACING_PIPELINE_CONFIG1 pipeline_config;
|
||||
D3D12_RAYTRACING_SHADER_CONFIG shader_config;
|
||||
|
||||
struct
|
||||
{
|
||||
|
@ -3424,10 +3439,16 @@ struct d3d12_state_object
|
|||
struct d3d12_state_object **collections;
|
||||
size_t collections_count;
|
||||
|
||||
struct d3d12_root_signature *global_root_signature;
|
||||
|
||||
struct vkd3d_private_store private_store;
|
||||
};
|
||||
|
||||
HRESULT d3d12_state_object_create(struct d3d12_device *device, const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent,
|
||||
struct d3d12_state_object **object);
|
||||
HRESULT d3d12_state_object_add(struct d3d12_device *device, const D3D12_STATE_OBJECT_DESC *desc,
|
||||
struct d3d12_state_object *parent,
|
||||
struct d3d12_state_object **object);
|
||||
|
||||
static inline struct d3d12_state_object *impl_from_ID3D12StateObject(ID3D12StateObject *iface)
|
||||
|
|
|
@ -1395,6 +1395,21 @@ static unsigned int rt_pso_factory_add_existing_collection(struct rt_pso_factory
|
|||
return rt_pso_factory_add_subobject(factory, &desc);
|
||||
}
|
||||
|
||||
static unsigned int rt_pso_factory_add_default_node_mask(struct rt_pso_factory* factory)
|
||||
{
|
||||
D3D12_STATE_SUBOBJECT desc;
|
||||
D3D12_NODE_MASK *mask;
|
||||
|
||||
mask = rt_pso_factory_calloc(factory, 1, sizeof(*mask));
|
||||
/* This node mask is weird and some runtimes have bugs. We'll just ignore it anyways in vkd3d-proton.
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_state_subobject_type */
|
||||
mask->NodeMask = 1;
|
||||
|
||||
desc.Type = D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK;
|
||||
desc.pDesc = mask;
|
||||
return rt_pso_factory_add_subobject(factory, &desc);
|
||||
}
|
||||
|
||||
static ID3D12StateObject *rt_pso_factory_compile(struct raytracing_test_context *context,
|
||||
struct rt_pso_factory *factory,
|
||||
D3D12_STATE_OBJECT_TYPE type)
|
||||
|
@ -1433,6 +1448,62 @@ static ID3D12StateObject *rt_pso_factory_compile(struct raytracing_test_context
|
|||
return rt_pso;
|
||||
}
|
||||
|
||||
static ID3D12StateObject *rt_pso_add_to_state_object(ID3D12Device5 *device, ID3D12StateObject *parent, ID3D12StateObject *addition,
|
||||
const D3D12_HIT_GROUP_DESC *hit_group)
|
||||
{
|
||||
D3D12_EXISTING_COLLECTION_DESC existing;
|
||||
ID3D12StateObject *new_state_object;
|
||||
D3D12_STATE_OBJECT_CONFIG config;
|
||||
D3D12_STATE_SUBOBJECT subobj[3];
|
||||
D3D12_STATE_OBJECT_DESC desc;
|
||||
ID3D12Device7 *device7;
|
||||
HRESULT hr;
|
||||
|
||||
desc.NumSubobjects = 1;
|
||||
desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE;
|
||||
desc.pSubobjects = subobj;
|
||||
subobj[0].Type = D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION;
|
||||
subobj[0].pDesc = &existing;
|
||||
existing.NumExports = 0;
|
||||
existing.pExports = NULL;
|
||||
existing.pExistingCollection = addition;
|
||||
|
||||
if (hit_group)
|
||||
{
|
||||
subobj[desc.NumSubobjects].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
|
||||
subobj[desc.NumSubobjects].pDesc = hit_group;
|
||||
desc.NumSubobjects++;
|
||||
}
|
||||
|
||||
if (FAILED(ID3D12Device5_QueryInterface(device, &IID_ID3D12Device7, (void**)&device7)))
|
||||
{
|
||||
skip("Failed to query ID3D12Device7.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Have to add ALLOW_STATE_OBJECT_ADDITIONS for both parent and addition. */
|
||||
hr = ID3D12Device7_AddToStateObject(device7, &desc, parent, &IID_ID3D12StateObject, (void**)&new_state_object);
|
||||
ok(hr == E_INVALIDARG, "Unexpected hr #%x.\n", hr);
|
||||
|
||||
config.Flags = D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS;
|
||||
subobj[desc.NumSubobjects].Type = D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;
|
||||
subobj[desc.NumSubobjects].pDesc = &config;
|
||||
desc.NumSubobjects++;
|
||||
|
||||
/* Type must be RAYTRACING_PIPELINE. */
|
||||
desc.Type = D3D12_STATE_OBJECT_TYPE_COLLECTION;
|
||||
hr = ID3D12Device7_AddToStateObject(device7, &desc, parent, &IID_ID3D12StateObject, (void**)&new_state_object);
|
||||
ok(hr == E_INVALIDARG, "Unexpected hr #%x.\n", hr);
|
||||
desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE;
|
||||
|
||||
hr = ID3D12Device7_AddToStateObject(device7, &desc, parent, &IID_ID3D12StateObject, (void**)&new_state_object);
|
||||
ok(SUCCEEDED(hr), "Failed to AddToStateObject, hr #%x.\n", hr);
|
||||
if (FAILED(hr))
|
||||
new_state_object = NULL;
|
||||
ID3D12Device7_Release(device7);
|
||||
return new_state_object;
|
||||
}
|
||||
|
||||
enum rt_test_mode
|
||||
{
|
||||
TEST_MODE_PLAIN,
|
||||
|
@ -1442,6 +1513,7 @@ enum rt_test_mode
|
|||
TEST_MODE_TRACE_RAY_SKIP_AABBS,
|
||||
TEST_MODE_PSO_SKIP_TRIANGLES,
|
||||
TEST_MODE_PSO_SKIP_AABBS,
|
||||
TEST_MODE_PSO_ADD_TO_STATE_OBJECT,
|
||||
};
|
||||
|
||||
static ID3D12StateObject *create_rt_collection(struct raytracing_test_context *context,
|
||||
|
@ -1454,8 +1526,19 @@ static ID3D12StateObject *create_rt_collection(struct raytracing_test_context *c
|
|||
|
||||
rt_pso_factory_init(&factory);
|
||||
|
||||
rt_pso_factory_add_state_object_config(&factory,
|
||||
rt_pso_factory_add_default_node_mask(&factory);
|
||||
|
||||
if (test_mode == TEST_MODE_PSO_ADD_TO_STATE_OBJECT)
|
||||
{
|
||||
rt_pso_factory_add_state_object_config(&factory,
|
||||
D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS |
|
||||
D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_pso_factory_add_state_object_config(&factory,
|
||||
D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS);
|
||||
}
|
||||
|
||||
if (test_mode == TEST_MODE_PSO_SKIP_TRIANGLES)
|
||||
rt_pso_factory_add_pipeline_config1(&factory, 1, D3D12_RAYTRACING_PIPELINE_FLAG_SKIP_TRIANGLES);
|
||||
|
@ -1527,6 +1610,7 @@ static void test_raytracing_pipeline(enum rt_test_mode mode, D3D12_RAYTRACING_TI
|
|||
ID3D12Resource *sbt_colors_buffer;
|
||||
ID3D12Resource *postbuild_buffer;
|
||||
unsigned int i, descriptor_size;
|
||||
ID3D12StateObject *rt_pso_added;
|
||||
ID3D12RootSignature *global_rs;
|
||||
struct test_geometry test_geom;
|
||||
ID3D12RootSignature *local_rs;
|
||||
|
@ -1687,8 +1771,12 @@ static void test_raytracing_pipeline(enum rt_test_mode mode, D3D12_RAYTRACING_TI
|
|||
unsigned int local_rs_index;
|
||||
|
||||
rt_pso_factory_init(&factory);
|
||||
rt_pso_factory_add_default_node_mask(&factory);
|
||||
|
||||
rt_pso_factory_add_state_object_config(&factory, D3D12_STATE_OBJECT_FLAG_NONE);
|
||||
if (mode == TEST_MODE_PSO_ADD_TO_STATE_OBJECT)
|
||||
rt_pso_factory_add_state_object_config(&factory, D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS);
|
||||
else
|
||||
rt_pso_factory_add_state_object_config(&factory, D3D12_STATE_OBJECT_FLAG_NONE);
|
||||
rt_pso_factory_add_global_root_signature(&factory, global_rs);
|
||||
|
||||
if (mode == TEST_MODE_PSO_SKIP_TRIANGLES)
|
||||
|
@ -1710,27 +1798,128 @@ static void test_raytracing_pipeline(enum rt_test_mode mode, D3D12_RAYTRACING_TI
|
|||
rt_pso_factory_add_subobject_to_exports_association(&factory,
|
||||
local_rs_index, 0, NULL);
|
||||
|
||||
rt_pso_factory_add_existing_collection(&factory, rt_object_library_tri, 0, NULL);
|
||||
rt_pso_factory_add_existing_collection(&factory, rt_object_library_aabb, 0, NULL);
|
||||
/* Defer this. */
|
||||
if (mode != TEST_MODE_PSO_ADD_TO_STATE_OBJECT)
|
||||
{
|
||||
rt_pso_factory_add_existing_collection(&factory, rt_object_library_tri, 0, NULL);
|
||||
rt_pso_factory_add_existing_collection(&factory, rt_object_library_aabb, 0, NULL);
|
||||
|
||||
memset(&hit_group, 0, sizeof(hit_group));
|
||||
hit_group.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES;
|
||||
hit_group.ClosestHitShaderImport = u"XRayClosest";
|
||||
hit_group.HitGroupExport = u"XRayHit2";
|
||||
rt_pso_factory_add_hit_group(&factory, &hit_group);
|
||||
}
|
||||
|
||||
rt_pso = rt_pso_factory_compile(&context, &factory, D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);
|
||||
|
||||
if (mode != TEST_MODE_PSO_ADD_TO_STATE_OBJECT)
|
||||
{
|
||||
/* Docs say there should be ref-count of the collection, but apparently, that refcount is private. */
|
||||
ref_count = ID3D12StateObject_AddRef(rt_object_library_tri);
|
||||
ok(ref_count == 2, "Collection ref count is %u.\n", ref_count);
|
||||
ID3D12StateObject_Release(rt_object_library_tri);
|
||||
|
||||
ref_count = ID3D12StateObject_AddRef(rt_object_library_aabb);
|
||||
ok(ref_count == 2, "Collection ref count is %u.\n", ref_count);
|
||||
ID3D12StateObject_Release(rt_object_library_aabb);
|
||||
}
|
||||
}
|
||||
else
|
||||
rt_pso = NULL;
|
||||
|
||||
/* Add two iterations of AddToStateObject so we have test coverage of that scenario. */
|
||||
if (mode == TEST_MODE_PSO_ADD_TO_STATE_OBJECT && rt_pso)
|
||||
{
|
||||
D3D12_HIT_GROUP_DESC hit_group;
|
||||
|
||||
memset(&hit_group, 0, sizeof(hit_group));
|
||||
hit_group.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES;
|
||||
hit_group.ClosestHitShaderImport = u"XRayClosest";
|
||||
hit_group.HitGroupExport = u"XRayHit2";
|
||||
rt_pso_factory_add_hit_group(&factory, &hit_group);
|
||||
|
||||
rt_pso = rt_pso_factory_compile(&context, &factory, D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);
|
||||
|
||||
/* Docs say there should be ref-count of the collection, but apparently, that refcount is private. */
|
||||
rt_pso_added = rt_pso_add_to_state_object(context.device5, rt_pso, rt_object_library_tri, &hit_group);
|
||||
ID3D12StateObject_Release(rt_pso);
|
||||
rt_pso = rt_pso_added;
|
||||
ref_count = ID3D12StateObject_AddRef(rt_object_library_tri);
|
||||
ok(ref_count == 2, "Collection ref count is %u.\n", ref_count);
|
||||
ID3D12StateObject_Release(rt_object_library_tri);
|
||||
}
|
||||
|
||||
if (mode == TEST_MODE_PSO_ADD_TO_STATE_OBJECT && rt_pso)
|
||||
{
|
||||
uint8_t pre_ray_miss_data[D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES];
|
||||
uint8_t pre_ray_gen_data[D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES];
|
||||
uint8_t pre_hit_data[D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES];
|
||||
ID3D12StateObjectProperties *combined_props;
|
||||
static const WCHAR ray_miss[] = u"XRayMiss";
|
||||
static const WCHAR ray_hit2[] = u"XRayHit2";
|
||||
static const WCHAR ray_gen[] = u"XRayGen";
|
||||
ID3D12StateObjectProperties *post_props;
|
||||
ID3D12StateObjectProperties *pre_props;
|
||||
|
||||
uint8_t *combined_ray_miss;
|
||||
uint8_t *combined_ray_gen;
|
||||
uint8_t *combined_hit;
|
||||
|
||||
uint8_t *post_ray_miss;
|
||||
uint8_t *post_ray_gen;
|
||||
uint8_t *post_hit;
|
||||
|
||||
uint8_t *pre_ray_miss;
|
||||
uint8_t *pre_ray_gen;
|
||||
uint8_t *pre_hit;
|
||||
|
||||
ID3D12StateObject_QueryInterface(rt_pso, &IID_ID3D12StateObjectProperties, (void**)&pre_props);
|
||||
|
||||
pre_ray_gen = ID3D12StateObjectProperties_GetShaderIdentifier(pre_props, ray_gen);
|
||||
pre_hit = ID3D12StateObjectProperties_GetShaderIdentifier(pre_props, ray_hit2);
|
||||
pre_ray_miss = ID3D12StateObjectProperties_GetShaderIdentifier(pre_props, ray_miss);
|
||||
memcpy(pre_ray_miss_data, pre_ray_miss, sizeof(pre_ray_miss_data));
|
||||
memcpy(pre_ray_gen_data, pre_ray_gen, sizeof(pre_ray_gen_data));
|
||||
memcpy(pre_hit_data, pre_hit, sizeof(pre_hit_data));
|
||||
|
||||
rt_pso_added = rt_pso_add_to_state_object(context.device5, rt_pso, rt_object_library_aabb, NULL);
|
||||
ID3D12StateObject_QueryInterface(rt_pso, &IID_ID3D12StateObjectProperties, (void**)&post_props);
|
||||
ID3D12StateObject_QueryInterface(rt_pso_added, &IID_ID3D12StateObjectProperties, (void**)&combined_props);
|
||||
|
||||
post_ray_gen = ID3D12StateObjectProperties_GetShaderIdentifier(post_props, ray_gen);
|
||||
post_hit = ID3D12StateObjectProperties_GetShaderIdentifier(post_props, ray_hit2);
|
||||
post_ray_miss = ID3D12StateObjectProperties_GetShaderIdentifier(post_props, ray_miss);
|
||||
|
||||
combined_ray_gen = ID3D12StateObjectProperties_GetShaderIdentifier(combined_props, ray_gen);
|
||||
combined_hit = ID3D12StateObjectProperties_GetShaderIdentifier(combined_props, ray_hit2);
|
||||
combined_ray_miss = ID3D12StateObjectProperties_GetShaderIdentifier(combined_props, ray_miss);
|
||||
|
||||
/* The docs do talk about taking some weird internal locks to deal with AddToStateObject(), so verify
|
||||
* that we don't have to return the parent property pointer here. */
|
||||
ok(pre_props == post_props, "Unexpected result in interface check.\n");
|
||||
ok(combined_props != post_props, "Unexpected result in interface check.\n");
|
||||
|
||||
ok(pre_ray_gen == post_ray_gen, "Unexpected SBT pointers.\n");
|
||||
ok(pre_hit == post_hit, "Unexpected SBT pointers.\n");
|
||||
ok(pre_ray_miss == post_ray_miss, "Unexpected SBT pointers.\n");
|
||||
|
||||
/* Apparently, we have to inherit the pointer to the SBT directly. */
|
||||
ok(combined_ray_gen == post_ray_gen, "Unexpected SBT pointers.\n");
|
||||
ok(combined_hit == post_hit, "Unexpected SBT pointers.\n");
|
||||
ok(combined_ray_miss == post_ray_miss, "Unexpected SBT pointers.\n");
|
||||
|
||||
/* Verify that we cannot modify the SBT data in place. */
|
||||
ok(memcmp(combined_hit, pre_hit_data, sizeof(pre_hit_data)) == 0, "Detected variance for existing SBT entries.\n");
|
||||
ok(memcmp(combined_ray_gen, pre_ray_gen_data, sizeof(pre_ray_gen_data)) == 0, "Detected variance for existing SBT entries.\n");
|
||||
ok(memcmp(combined_ray_miss, pre_ray_miss_data, sizeof(pre_ray_miss_data)) == 0, "Detected variance for existing SBT entries.\n");
|
||||
|
||||
ID3D12StateObject_Release(rt_pso);
|
||||
rt_pso = rt_pso_added;
|
||||
ref_count = ID3D12StateObject_AddRef(rt_object_library_aabb);
|
||||
ok(ref_count == 2, "Collection ref count is %u.\n", ref_count);
|
||||
ID3D12StateObject_Release(rt_object_library_aabb);
|
||||
|
||||
ID3D12StateObjectProperties_Release(pre_props);
|
||||
ID3D12StateObjectProperties_Release(post_props);
|
||||
ID3D12StateObjectProperties_Release(combined_props);
|
||||
}
|
||||
else
|
||||
rt_pso = NULL;
|
||||
|
||||
/* Docs say that refcount should be held by RTPSO, but apparently it doesn't on native drivers. */
|
||||
ID3D12RootSignature_AddRef(global_rs);
|
||||
|
@ -2197,6 +2386,7 @@ void test_raytracing(void)
|
|||
{ TEST_MODE_TRACE_RAY_SKIP_AABBS, D3D12_RAYTRACING_TIER_1_1, "TraceRaySkipAABBs" },
|
||||
{ TEST_MODE_PSO_SKIP_TRIANGLES, D3D12_RAYTRACING_TIER_1_1, "PSOSkipTriangles" },
|
||||
{ TEST_MODE_PSO_SKIP_AABBS, D3D12_RAYTRACING_TIER_1_1, "PSOSkipAABBs" },
|
||||
{ TEST_MODE_PSO_ADD_TO_STATE_OBJECT, D3D12_RAYTRACING_TIER_1_1, "AddToStateObject" },
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
|
Loading…
Reference in New Issue