Skip to content

Commit 12af9b6

Browse files
layers: Fix PTLAS descriptor handling and overlap validation (#11584)
* layers: Fix PTLAS descriptor handling and overlap validation tests: Fix some VUIDs and added more PTLAS coverage * tests: Update testicd --------- Co-authored-by: spencer-lunarg <[email protected]>
1 parent 472d81b commit 12af9b6

File tree

12 files changed

+140
-26
lines changed

12 files changed

+140
-26
lines changed

layers/best_practices/bp_pipeline.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ bool BestPractices::PreCallValidateCreatePipelineLayout(VkDevice device, const V
416416
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
417417
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
418418
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
419+
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
419420
descriptor_type_size = 8;
420421
break;
421422
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:

layers/chassis/dispatch_object_manual.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,12 @@ void *BuildUnwrappedUpdateTemplateBuffer(Device *layer_data, uint64_t descriptor
16091609
template_entries.emplace_back(offset, kVulkanObjectTypeAccelerationStructureKHR, CastToUint64(wrapped_entry),
16101610
0);
16111611
} break;
1612+
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV: {
1613+
// PTLAS uses VkDeviceAddress directly, not an opaque handle - no unwrapping needed
1614+
allocation_size = std::max(allocation_size, offset + sizeof(VkDeviceAddress));
1615+
template_entries.emplace_back(offset, kVulkanObjectTypeUnknown, CastToUint64(update_entry),
1616+
sizeof(VkDeviceAddress));
1617+
} break;
16121618
default:
16131619
assert(false);
16141620
break;
@@ -2287,6 +2293,7 @@ void Device::GetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pDe
22872293
break;
22882294
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
22892295
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
2296+
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
22902297
local_pDescriptorInfo.data.accelerationStructure = pDescriptorInfo->data.accelerationStructure;
22912298
break;
22922299
default:

layers/core_checks/cc_descriptor.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,7 @@ vvl::DecodedTemplateUpdate::DecodedTemplateUpdate(const vvl::DeviceState &device
15041504
inline_infos.resize(create_info.descriptorUpdateEntryCount); // Make sure we have one if we need it
15051505
inline_infos_khr.resize(create_info.descriptorUpdateEntryCount);
15061506
inline_infos_nv.resize(create_info.descriptorUpdateEntryCount);
1507+
inline_infos_ptlas.resize(create_info.descriptorUpdateEntryCount);
15071508
desc_writes.reserve(create_info.descriptorUpdateEntryCount); // emplaced, so reserved without initialization
15081509
VkDescriptorSetLayout effective_dsl = create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
15091510
? create_info.descriptorSetLayout
@@ -1594,6 +1595,17 @@ vvl::DecodedTemplateUpdate::DecodedTemplateUpdate(const vvl::DeviceState &device
15941595
write_entry.descriptorCount = inline_info_nv->accelerationStructureCount;
15951596
break;
15961597
}
1598+
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV: {
1599+
VkWriteDescriptorSetPartitionedAccelerationStructureNV *inline_info_ptlas = &inline_infos_ptlas[i];
1600+
inline_info_ptlas->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_PARTITIONED_ACCELERATION_STRUCTURE_NV;
1601+
inline_info_ptlas->pNext = nullptr;
1602+
inline_info_ptlas->accelerationStructureCount = descriptor_update_entry.descriptorCount;
1603+
inline_info_ptlas->pAccelerationStructures = reinterpret_cast<const VkDeviceAddress *>(update_entry);
1604+
write_entry.pNext = inline_info_ptlas;
1605+
// descriptorCount must match the accelerationStructureCount
1606+
write_entry.descriptorCount = inline_info_ptlas->accelerationStructureCount;
1607+
break;
1608+
}
15971609
default:
15981610
assert(false);
15991611
break;
@@ -1603,7 +1615,8 @@ vvl::DecodedTemplateUpdate::DecodedTemplateUpdate(const vvl::DeviceState &device
16031615
// If acceleration structure, we only create a single VkWriteDescriptorSet and map the actually AS into
16041616
// VkWriteDescriptorSetAccelerationStructureKHR
16051617
if (descriptor_update_entry.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
1606-
descriptor_update_entry.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV) {
1618+
descriptor_update_entry.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV ||
1619+
descriptor_update_entry.descriptorType == VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV) {
16071620
break;
16081621
}
16091622
}
@@ -5475,8 +5488,7 @@ bool CoreChecks::PreCallValidateWriteResourceDescriptorsEXT(VkDevice device, uin
54755488
skip |=
54765489
ValidateDeviceAddressRange(address_range.address, address_range.size, false, data_loc.dot(Field::pAddressRange),
54775490
LogObjectList(device), buffer_usage, usage_vuid);
5478-
} else if (resource.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
5479-
resource.type == VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV) {
5491+
} else if (resource.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) {
54805492
// TODO - not sure what this covers that VUID-VkResourceDescriptorInfoEXT-type-11484 doesn't
54815493
if (auto as_array = GetAccelerationStructuresByAddress(address_range.address); as_array.empty()) {
54825494
std::stringstream ss;
@@ -5496,6 +5508,13 @@ bool CoreChecks::PreCallValidateWriteResourceDescriptorsEXT(VkDevice device, uin
54965508
skip |= LogError("VUID-VkResourceDescriptorInfoEXT-type-11483", device,
54975509
data_loc.dot(Field::pAddressRange).dot(Field::address), "%s", ss.str().c_str());
54985510
}
5511+
} else if (resource.type == VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV) {
5512+
// PTLAS uses buffer addresses directly, not VkAccelerationStructureKHR objects
5513+
// Validate that the address points to a buffer with ACCELERATION_STRUCTURE_STORAGE_BIT
5514+
skip |= ValidateDeviceAddressRange(address_range.address, address_range.size, false,
5515+
data_loc.dot(Field::pAddressRange), LogObjectList(device),
5516+
VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
5517+
"VUID-VkResourceDescriptorInfoEXT-type-11483");
54995518
} else if (resource.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV) {
55005519
if (address_range.size != 0) {
55015520
skip |= LogError("VUID-VkResourceDescriptorInfoEXT-type-11468", device,

layers/core_checks/cc_ray_tracing.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,22 +2453,26 @@ bool CoreChecks::PreCallValidateCmdBuildPartitionedAccelerationStructuresNV(
24532453
}
24542454
}
24552455

2456-
if (pBuildInfo->srcAccelerationStructureData && pBuildInfo->dstAccelerationStructureData) {
2456+
// Check for src vs dst overlap, but only if they are different addresses (in-place update is allowed)
2457+
if (pBuildInfo->srcAccelerationStructureData && pBuildInfo->dstAccelerationStructureData &&
2458+
pBuildInfo->srcAccelerationStructureData != pBuildInfo->dstAccelerationStructureData) {
24572459
const auto src_buffer_states = GetBuffersByAddress(pBuildInfo->srcAccelerationStructureData);
24582460
const auto dst_buffer_states = GetBuffersByAddress(pBuildInfo->dstAccelerationStructureData);
24592461
for (const auto &src_buffer_state : src_buffer_states) {
2460-
vvl::range<VkDeviceAddress> src_address_range = src_buffer_state->DeviceAddressRange();
2462+
const vvl::range<VkDeviceAddress> src_address_range = src_buffer_state->DeviceAddressRange();
24612463
if (!src_address_range.empty()) {
2462-
for (const auto &buffer_state : dst_buffer_states) {
2463-
const vvl::range<VkDeviceAddress> buffer_address_range = buffer_state->DeviceAddressRange();
2464-
if (buffer_address_range.intersects(src_address_range)) {
2465-
const LogObjectList objlist(commandBuffer, buffer_state->Handle(), src_buffer_state->Handle());
2466-
skip |=
2467-
LogError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10549", objlist,
2468-
error_obj.location.dot(Field::pBuildInfo).dot(Field::dstAccelerationStructureData),
2469-
"%s address range %s intersects srcAccelerationStructureData address range %s",
2470-
FormatHandle(buffer_state->Handle()).c_str(), string_range_hex(buffer_address_range).c_str(),
2471-
string_range_hex(src_address_range).c_str());
2464+
for (const auto &dst_buffer_state : dst_buffer_states) {
2465+
const vvl::range<VkDeviceAddress> dst_address_range = dst_buffer_state->DeviceAddressRange();
2466+
if (src_address_range.intersects(dst_address_range)) {
2467+
const LogObjectList objlist(commandBuffer, src_buffer_state->Handle(), dst_buffer_state->Handle());
2468+
skip |= LogError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10549", objlist,
2469+
error_obj.location.dot(Field::pBuildInfo),
2470+
"srcAccelerationStructureData %s address range %s intersects "
2471+
"dstAccelerationStructureData %s address range %s",
2472+
FormatHandle(src_buffer_state->Handle()).c_str(),
2473+
string_range_hex(src_address_range).c_str(),
2474+
FormatHandle(dst_buffer_state->Handle()).c_str(),
2475+
string_range_hex(dst_address_range).c_str());
24722476
}
24732477
}
24742478
}

layers/core_checks/cc_spirv.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,13 @@ static void TypeToDescriptorTypeSet(const spirv::Module &module_state, uint32_t
384384

385385
// The OpType are alias, but the Descriptor Types are different
386386
case spv::OpTypeAccelerationStructureKHR:
387-
// Only KHR or NV base accelleration structure is selected
387+
// Only KHR or NV base acceleration structure is selected
388388
if (module_state.HasCapability(spv::CapabilityRayTracingNV)) {
389389
out_data.descriptor_type_set.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
390390
} else {
391391
out_data.descriptor_type_set.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
392392
}
393-
393+
// Additionally allow PTLAS if shader uses cluster acceleration structure features
394394
if (module_state.HasCapability(spv::CapabilityRayTracingClusterAccelerationStructureNV)) {
395395
out_data.descriptor_type_set.insert(VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV);
396396
}
@@ -3637,4 +3637,4 @@ bool CoreChecks::ValidateDescriptorHeapStructs(const spirv::Module &module_state
36373637
}
36383638

36393639
return skip;
3640-
}
3640+
}

layers/object_tracker/object_lifetime_validation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ bool Device::ValidateDescriptorWrite(VkWriteDescriptorSet const *desc, bool is_p
541541
break;
542542
}
543543

544-
// VkWriteDescriptorSetPartitionedAccelerationStructureNV contains no VkObjects to validate
544+
// PTLAS uses VkDeviceAddress values, not VkAccelerationStructureKHR handles - no objects to validate
545545
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
546546
// Inline has no objects, so nothing to validate
547547
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:

layers/state_tracker/descriptor_sets.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,7 @@ struct DecodedTemplateUpdate {
844844
std::vector<VkWriteDescriptorSetInlineUniformBlock> inline_infos;
845845
std::vector<VkWriteDescriptorSetAccelerationStructureKHR> inline_infos_khr;
846846
std::vector<VkWriteDescriptorSetAccelerationStructureNV> inline_infos_nv;
847+
std::vector<VkWriteDescriptorSetPartitionedAccelerationStructureNV> inline_infos_ptlas;
847848
DecodedTemplateUpdate(const DeviceState &device_data, VkDescriptorSet descriptorSet,
848849
const DescriptorUpdateTemplate &template_state, const void *pData,
849850
VkDescriptorSetLayout push_layout = VK_NULL_HANDLE);

layers/sync/sync_commandbuffer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ static SyncAccessIndex GetSyncStageAccessIndexsByDescriptorSet(VkDescriptorType
195195
if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
196196
return stage_accesses.uniform_read;
197197
}
198-
if (descriptor_type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) {
198+
if (descriptor_type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
199+
descriptor_type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV ||
200+
descriptor_type == VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV) {
199201
return stage_accesses.acceleration_structure_read;
200202
}
201203

tests/icd/test_icd.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** Copyright (c) 2015-2018, 2023-2025 The Khronos Group Inc.
2+
** Copyright (c) 2015-2018, 2023-2026 The Khronos Group Inc.
33
** Modifications Copyright (C) 2024-2026 Advanced Micro Devices, Inc. All rights reserved.
44
**
55
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -2010,6 +2010,7 @@ static VKAPI_ATTR VkDeviceSize VKAPI_CALL GetPhysicalDeviceDescriptorSizeEXT(VkP
20102010
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
20112011
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
20122012
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
2013+
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
20132014
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
20142015
case VK_DESCRIPTOR_TYPE_TENSOR_ARM:
20152016
return 256;

tests/unit/descriptor_heap_positive.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3578,4 +3578,33 @@ TEST_F(PositiveDescriptorHeap, SingleElementNoArray) {
35783578
uint32_t* data = static_cast<uint32_t*>(buffer.Memory().Map());
35793579
ASSERT_EQ(data[0], src_data);
35803580
}
3581+
}
3582+
3583+
TEST_F(PositiveDescriptorHeap, PartitionedAccelerationStructure) {
3584+
TEST_DESCRIPTION("Test WriteResourceDescriptorsEXT with PTLAS descriptor type");
3585+
SetTargetApiVersion(VK_API_VERSION_1_2);
3586+
AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
3587+
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
3588+
AddRequiredFeature(vkt::Feature::accelerationStructure);
3589+
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
3590+
AddRequiredFeature(vkt::Feature::partitionedAccelerationStructure);
3591+
RETURN_IF_SKIP(InitBasicDescriptorHeap());
3592+
3593+
const VkDeviceSize descriptor_size =
3594+
vk::GetPhysicalDeviceDescriptorSizeEXT(gpu_, VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV);
3595+
std::vector<uint8_t> data(static_cast<size_t>(descriptor_size));
3596+
3597+
// Create buffer with required usage flags for PTLAS
3598+
vkt::Buffer ptlas_buffer(*m_device, 4096,
3599+
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
3600+
vkt::device_address);
3601+
3602+
VkDeviceAddressRangeEXT device_address_range = {ptlas_buffer.Address(), descriptor_size};
3603+
3604+
VkResourceDescriptorInfoEXT resource_info = vku::InitStructHelper();
3605+
resource_info.type = VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV;
3606+
resource_info.data.pAddressRange = &device_address_range;
3607+
3608+
VkHostAddressRangeEXT descriptor = {data.data(), static_cast<size_t>(descriptor_size)};
3609+
vk::WriteResourceDescriptorsEXT(*m_device, 1u, &resource_info, &descriptor);
35813610
}

0 commit comments

Comments
 (0)