Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions layers/gpuav/core/gpuav_features.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Copyright (c) 2025 The Khronos Group Inc.
* Copyright (c) 2025 Valve Corporation
* Copyright (c) 2025 LunarG, Inc.
/* Copyright (c) 2026 The Khronos Group Inc.
* Copyright (c) 2026 Valve Corporation
* Copyright (c) 2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -60,7 +60,8 @@ void Instance::AddFeatures(VkPhysicalDevice physical_device, vku::safe_VkDeviceC
VkPhysicalDeviceCooperativeMatrixFeaturesKHR supported_coop_mat_feature = vku::InitStructHelper();
VkPhysicalDeviceRobustness2FeaturesKHR supported_robustness2_feature = vku::InitStructHelper(&supported_coop_mat_feature);
VkPhysicalDevice8BitStorageFeatures supported_8bit_feature = vku::InitStructHelper(&supported_robustness2_feature);
VkPhysicalDeviceBufferDeviceAddressFeatures supported_bda_feature = vku::InitStructHelper(&supported_8bit_feature);
VkPhysicalDevice16BitStorageFeatures supported_16bit_feature = vku::InitStructHelper(&supported_8bit_feature);
VkPhysicalDeviceBufferDeviceAddressFeatures supported_bda_feature = vku::InitStructHelper(&supported_16bit_feature);
VkPhysicalDeviceScalarBlockLayoutFeatures supported_scalar_feature = vku::InitStructHelper(&supported_bda_feature);
VkPhysicalDeviceVulkanMemoryModelFeatures supported_memory_model_feature = vku::InitStructHelper(&supported_scalar_feature);
VkPhysicalDeviceTimelineSemaphoreFeatures supported_timeline_feature = vku::InitStructHelper(&supported_memory_model_feature);
Expand Down Expand Up @@ -297,6 +298,42 @@ void Instance::AddFeatures(VkPhysicalDevice physical_device, vku::safe_VkDeviceC
}
}

if (supported_16bit_feature.storageBuffer16BitAccess) {
auto add_16bit_access = [modified_create_info, &adjustment_warnings]() {
// Add storageBuffer16BitAccess feature
if (auto *sixteen_bit_access_feature = const_cast<VkPhysicalDevice16BitStorageFeatures *>(
vku::FindStructInPNextChain<VkPhysicalDevice16BitStorageFeatures>(modified_create_info))) {
if (!sixteen_bit_access_feature->storageBuffer16BitAccess) {
adjustment_warnings += "\tForcing VkPhysicalDevice16BitStorageFeatures::storageBuffer16BitAccess to VK_TRUE\n";
sixteen_bit_access_feature->storageBuffer16BitAccess = VK_TRUE;
}
} else {
adjustment_warnings +=
"\tAdding a VkPhysicalDevice16BitStorageFeatures to pNext with storageBuffer16BitAccess "
"set to VK_TRUE\n";
VkPhysicalDevice16BitStorageFeatures new_16bit_features = vku::InitStructHelper();
new_16bit_features.storageBuffer16BitAccess = VK_TRUE;
vku::AddToPnext(*modified_create_info, new_16bit_features);
}
};

if (api_version >= VK_API_VERSION_1_2) {
if (auto *features12 = const_cast<VkPhysicalDeviceVulkan11Features *>(
vku::FindStructInPNextChain<VkPhysicalDeviceVulkan11Features>(modified_create_info->pNext))) {
if (!features12->storageBuffer16BitAccess) {
adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan11Features::storageBuffer16BitAccess to VK_TRUE\n";
features12->storageBuffer16BitAccess = VK_TRUE;
}
} else {
add_16bit_access();
}
} else if (IsExtensionAvailable(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, available_extensions)) {
// Only adds if not found already
vku::AddExtension(*modified_create_info, VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
add_16bit_access();
}
}

if (gpuav_settings.debug_printf_enabled) {
if (!IsExtensionAvailable(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, available_extensions)) {
adjustment_warnings +=
Expand Down
3 changes: 2 additions & 1 deletion layers/gpuav/core/gpuav_record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,8 @@ void Validator::PreCallRecordCmdBuildAccelerationStructuresKHR(
}
auto &cb_sub_state = SubState(*cb_state);
const LastBound &last_bound = cb_state->GetLastBoundRayTracing();
valcmd::BuildAccelerationStructures(*this, record_obj.location, cb_sub_state, last_bound, infoCount, pInfos, ppBuildRangeInfos);
valcmd::TLAS(*this, record_obj.location, cb_sub_state, last_bound, infoCount, pInfos, ppBuildRangeInfos);
valcmd::BLAS(*this, record_obj.location, cb_sub_state, last_bound, infoCount, pInfos, ppBuildRangeInfos);
}

void Validator::PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer,
Expand Down
13 changes: 8 additions & 5 deletions layers/gpuav/core/gpuav_setup.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Copyright (c) 2018-2025 The Khronos Group Inc.
* Copyright (c) 2018-2025 Valve Corporation
* Copyright (c) 2018-2025 LunarG, Inc.
/* Copyright (c) 2018-2026 The Khronos Group Inc.
* Copyright (c) 2018-2026 Valve Corporation
* Copyright (c) 2018-2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -388,10 +388,13 @@ struct BufferContent : public Setting {
struct AccelerationStructuresBuild : public Setting {
bool IsEnabled(const GpuAVSettings &settings) { return settings.validate_acceleration_structures_builds; }
// Validation shader branches on a push constant value to fetch different descriptors
bool HasRequiredFeatures(const DeviceFeatures &features) { return features.shaderInt64; }
bool HasRequiredFeatures(const DeviceFeatures &features) {
return features.shaderInt64 && features.storageBuffer8BitAccess && features.storageBuffer16BitAccess;
}
void Disable(GpuAVSettings &settings) { settings.validate_acceleration_structures_builds = false; }
std::string DisableMessage() {
return "\t structure builds validation option was enabled, but the shaderInt64 feature is not "
return "\t structure builds validation option was enabled, but the shaderInt64 or storageBuffer8BitAccess or "
"storageBuffer16BitAccess features are not "
"supported. [Disabling "
"gpuav_acceleration_structures_builds]\n";
}
Expand Down
1 change: 1 addition & 0 deletions layers/gpuav/shaders/gpuav_error_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ const int kErrorSubCode_PreBuildAccelerationStructures_DestroyedASBuffer = 3;
const int kErrorSubCode_PreBuildAccelerationStructures_InvalidASType = 4;
const int kErrorSubCode_PreBuildAccelerationStructures_DestroyedASMemory = 5;
const int kErrorSubCode_PreBuildAccelerationStructures_BlasMemoryOverlap = 6;
const int kErrorSubCode_PreBuildAccelerationStructures_MaxFetchedIndex = 7;

#ifdef __cplusplus
} // namespace glsl
Expand Down
85 changes: 85 additions & 0 deletions layers/gpuav/shaders/validation_cmd/blas.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) 2022-2026 The Khronos Group Inc.
// Copyright (c) 2022-2026 Valve Corporation
// Copyright (c) 2022-2026 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#version 460
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require

#include "common.h"
#include "build_acceleration_structures.h"

layout(push_constant, scalar)
uniform PushConstants {
BLASValidationShaderPushData pc;
};

// CPU will try to dispatch `primitive_count` threads
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

layout(buffer_reference, scalar) buffer ArrayU8 { uint8_t array[]; };
layout(buffer_reference, scalar) buffer ArrayU16 { uint16_t array[]; };
layout(buffer_reference, scalar) buffer ArrayU32 { uint array[]; };

// From VkIndexType
const uint VK_INDEX_TYPE_UINT16 = 0;
const uint VK_INDEX_TYPE_UINT32 = 1;
const uint VK_INDEX_TYPE_UINT8 = 1000265000;
const uint VK_INDEX_TYPE_NONE_KHR = 1000165000;

uint LoadIndex(uint i) {
if (pc.index_type == VK_INDEX_TYPE_UINT16) {
ArrayU16 array_u16 = ArrayU16(pc.index_data + pc.primitive_offset);
return uint(array_u16.array[i]);
} else if (pc.index_type == VK_INDEX_TYPE_UINT32) {
ArrayU32 array_u32 = ArrayU32(pc.index_data + pc.primitive_offset);
return array_u32.array[i];
} else if (pc.index_type == VK_INDEX_TYPE_UINT8) {
ArrayU8 array_u8 = ArrayU8(pc.index_data + pc.primitive_offset);
return uint(array_u8.array[i]);
} else {
return 0;
}
}

void StoreIndex(uint i, uint value) {
if (pc.index_type == VK_INDEX_TYPE_UINT16) {
ArrayU16 array_u16 = ArrayU16(pc.index_data + pc.primitive_offset);
array_u16.array[i] = uint16_t(value);
} else if (pc.index_type == VK_INDEX_TYPE_UINT32) {
ArrayU32 array_u32 = ArrayU32(pc.index_data + pc.primitive_offset);
array_u32.array[i] = value;
} else if (pc.index_type == VK_INDEX_TYPE_UINT8) {
ArrayU8 array_u8 = ArrayU8(pc.index_data + pc.primitive_offset);
array_u8.array[i] = uint8_t(value);
}
}


void main() {
const uint gid = gl_GlobalInvocationID.x;

if (gid >= (3 * pc.primitive_count)) {
return;
}
const uint fetched_index = LoadIndex(gid);
if (pc.max_vertex < (pc.first_vertex + fetched_index)) {
// In practice an invalid index does not cause a device loss, so don't bother changing its value.
// Should someone add this back, a write barrier needs to be added on the CPU side.
// StoreIndex(gid, 0);
GpuavLogError4(kErrorGroup_GpuPreBuildAccelerationStructures, kErrorSubCode_PreBuildAccelerationStructures_MaxFetchedIndex, fetched_index, gid, pc.error_info_i, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ layout(buffer_reference, scalar) buffer PtrToBlasBuiltInCmd { Range buffer_range
const uint kBuildASValidationMode_invalid_AS = 0;
const uint kBuildASValidationMode_memory_overlaps = 1;

// Case where arrayOfPointers is false
struct AccelerationStructureReferencePushData {
struct TLASValidationShaderPushData {
PtrtoPtrToAccelerationStructureArrays ptr_to_ptr_to_accel_structs_arrays;
uint64_t valid_dummy_blas_addr;

Expand All @@ -125,6 +124,16 @@ struct AccelerationStructureReferencePushData {
uint blas_built_in_cmd_array_size;
};

struct BLASValidationShaderPushData {
uint64_t index_data; // Cast it appropriately according to index_type
uint index_type;
uint max_vertex;
uint first_vertex;
uint primitive_offset;
uint primitive_count;
uint error_info_i;
};

#ifdef __cplusplus
} // namespace glsl
} // namespace gpuav
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

layout(push_constant, scalar)
uniform PushConstants {
AccelerationStructureReferencePushData pc;
TLASValidationShaderPushData pc;
};

bool RangesInclude(Range r1, Range r2) {
Expand Down
Loading