1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
// 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;
}
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);
}
}
|