blob: 0644e057b8c1bb5b6c17b50c3bd559cfb4afc625 [file]
// 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
#include "common.h"
#include "build_acceleration_structures.h"
layout(push_constant, scalar)
uniform PushConstants {
TLASValidationShaderPushData pc;
};
bool RangesInclude(Range r1, Range r2) {
return (r1.begin <= r2.begin) && (r2.end <= r1.end);
}
bool RangesOverlap(Range r1, Range r2) {
return RangesInclude(r1, r2) || RangesInclude(r2, r1);
}
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main() {
uint as_instance_i = 0;
if (pc.validation_mode == kBuildASValidationMode_invalid_AS) {
as_instance_i = gl_GlobalInvocationID.x * (gl_NumWorkGroups.y * gl_WorkGroupSize.y) + gl_GlobalInvocationID.y;
} else if (pc.validation_mode == kBuildASValidationMode_memory_overlaps) {
as_instance_i = gl_GlobalInvocationID.x;
}
if (as_instance_i >= pc.blas_array_size) {
return;
}
const uint blas_built_in_cmd_i = gl_GlobalInvocationID.y;
// Address of BLAS to validate
uint64_t blas_addr = 0;
if (pc.is_array_of_pointers == 0) {
blas_addr = pc.blas_array_start_addr.blas_array[as_instance_i].accelerationStructureReference;
} else {
blas_addr = pc.blas_ptr_array_start_addr.blas_ptr_array[as_instance_i].as_instance.accelerationStructureReference;
}
// At least mentioned in VUID 12281:
// A BLAS address of 0 is valid
if (blas_addr == 0) {
return;
}
uint error_subcode = 0;
if ((blas_addr % 16u ) != 0) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_BlasAddrAlignment;
} else if (pc.validation_mode == kBuildASValidationMode_invalid_AS) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_InvalidAS;
const uint as_count = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.addresses_ptr.count;
for (uint as_i = 0; as_i < as_count; ++as_i) {
uint64_t valid_as_addr = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.addresses_ptr.array[as_i];
if (valid_as_addr == blas_addr) {
const uint as_metadata = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.metadata_ptr.array[as_i];
// found AS, first assume it is valid
error_subcode = 0;
if (GET_BUILD_AS_METADATA_BUFFER_STATUS(as_metadata) != BUILD_AS_METADATA_VALID_BUFFER) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_DestroyedASBuffer;
break;
}
if (GET_BUILD_AS_METADATA_AS_TYPE(as_metadata) != BUILD_AS_METADATA_AS_TYPE_BLAS) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_InvalidASType;
break;
}
if (GET_BUILD_AS_METADATA_BUFFER_MEMORY_STATUS(as_metadata) != BUILD_AS_METADATA_VALID_BUFFER_MEMORY) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_DestroyedASMemory;
break;
}
break;
}
}
} else if (pc.validation_mode == kBuildASValidationMode_memory_overlaps) {
if (blas_built_in_cmd_i >= pc.blas_built_in_cmd_array_size) {
return;
}
// Try to find buffer range associated to BLAS to validate
Range blas_buffer_range = {0,0};
const uint as_count = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.addresses_ptr.count;
for (uint as_i = 0; as_i < as_count; ++as_i) {
uint64_t valid_as_addr = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.addresses_ptr.array[as_i];
if (valid_as_addr == blas_addr) {
blas_buffer_range = pc.ptr_to_ptr_to_accel_structs_arrays.as_arrays_ptrs.buffer_ranges_ptr.array[as_i];
break;
}
}
// Does BLAS buffer range, referenced in a TLAS build,
// overlaps with another BLAS buffer range referenced in the same build command?
if (blas_buffer_range.begin != 0) {
Range blas_built_in_cmd_buffer_range = pc.blas_built_in_cmd_array_ptr.buffer_ranges[blas_built_in_cmd_i];
if (RangesOverlap(blas_buffer_range, blas_built_in_cmd_buffer_range)) {
error_subcode = kErrorSubCode_PreBuildAccelerationStructures_BlasMemoryOverlap;
}
}
}
if (error_subcode != 0) {
pc.blas_array_start_addr.blas_array[as_instance_i].instanceCustomIndex_and_mask &= 0xffffff;// Set mask to 0 (upper 8 bits), so instance cannot get hit
pc.blas_array_start_addr.blas_array[as_instance_i].accelerationStructureReference = pc.valid_dummy_blas_addr;// Point to a valid dummy blas
const uint error_dword_0 = uint(blas_addr);
const uint error_dword_1 = uint(blas_addr >> 32u);
const uint error_dword_2 = as_instance_i;
const uint error_dword_3 = pc.blas_array_i;// #ARNO_TODO swap dwords 2 and 3
const uint error_dword_4 = blas_built_in_cmd_i;
GpuavLogError5(kErrorGroup_GpuPreBuildAccelerationStructures, error_subcode, error_dword_0, error_dword_1, error_dword_2, error_dword_3, error_dword_4);
}
}