| /* Copyright (c) 2015-2023 The Khronos Group Inc. |
| * Copyright (c) 2015-2023 Valve Corporation |
| * Copyright (c) 2015-2023 LunarG, Inc. |
| * Copyright (C) 2015-2023 Google Inc. |
| * Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved. |
| * |
| * 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. |
| */ |
| |
| #include <algorithm> |
| #include <assert.h> |
| #include <sstream> |
| #include <string> |
| |
| #include <vulkan/vk_enum_string_helper.h> |
| #include "generated/chassis.h" |
| #include "core_validation.h" |
| #include "cc_buffer_address.h" |
| #include "utils/ray_tracing_utils.h" |
| |
| bool CoreChecks::ValidateInsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, const DEVICE_MEMORY_STATE *mem_info, |
| VkDeviceSize mem_offset, const Location &loc) const { |
| return ValidateInsertMemoryRange(VulkanTypedHandle(as, kVulkanObjectTypeAccelerationStructureNV), mem_info, mem_offset, loc); |
| } |
| |
| bool CoreChecks::PreCallValidateCreateAccelerationStructureNV(VkDevice device, |
| const VkAccelerationStructureCreateInfoNV *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkAccelerationStructureNV *pAccelerationStructure, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| if (pCreateInfo != nullptr && pCreateInfo->info.type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV) { |
| for (uint32_t i = 0; i < pCreateInfo->info.geometryCount; i++) { |
| skip |= ValidateGeometryNV(pCreateInfo->info.pGeometries[i], |
| error_obj.location.dot(Field::pCreateInfo).dot(Field::info).dot(Field::pGeometries, i)); |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCreateAccelerationStructureKHR(VkDevice device, |
| const VkAccelerationStructureCreateInfoKHR *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkAccelerationStructureKHR *pAccelerationStructure, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| if (!pCreateInfo) { |
| return false; |
| } |
| auto buffer_state = Get<BUFFER_STATE>(pCreateInfo->buffer); |
| if (!buffer_state) { |
| return false; |
| } |
| |
| if (!(buffer_state->usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR)) { |
| skip |= LogError("VUID-VkAccelerationStructureCreateInfoKHR-buffer-03614", buffer_state->Handle(), |
| error_obj.location.dot(Field::pCreateInfo).dot(Field::buffer), "was created with %s.", |
| string_VkBufferUsageFlags2KHR(buffer_state->usage).c_str()); |
| } |
| if (buffer_state->createInfo.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) { |
| skip |= LogError("VUID-VkAccelerationStructureCreateInfoKHR-buffer-03615", buffer_state->Handle(), |
| error_obj.location.dot(Field::pCreateInfo).dot(Field::buffer), "was created with %s.", |
| string_VkBufferCreateFlags(buffer_state->createInfo.flags).c_str()); |
| } |
| if (pCreateInfo->offset + pCreateInfo->size > buffer_state->createInfo.size) { |
| skip |= LogError("VUID-VkAccelerationStructureCreateInfoKHR-offset-03616", buffer_state->Handle(), |
| error_obj.location.dot(Field::pCreateInfo).dot(Field::offset), |
| "(%" PRIu64 ") plus size (%" PRIu64 ") must be less than the size of buffer (%" PRIu64 ").", |
| pCreateInfo->offset, pCreateInfo->size, buffer_state->createInfo.size); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount, |
| const VkBindAccelerationStructureMemoryInfoNV *pBindInfos, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| for (uint32_t i = 0; i < bindInfoCount; i++) { |
| const Location bind_info_loc = error_obj.location.dot(Field::pBindInfos, i); |
| const VkBindAccelerationStructureMemoryInfoNV &info = pBindInfos[i]; |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(info.accelerationStructure); |
| if (!as_state) { |
| continue; |
| } |
| if (as_state->HasFullRangeBound()) { |
| skip |= LogError("VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-03620", info.accelerationStructure, |
| bind_info_loc.dot(Field::accelerationStructure), "must not already be backed by a memory object."); |
| } |
| |
| // Validate bound memory range information |
| auto mem_info = Get<DEVICE_MEMORY_STATE>(info.memory); |
| if (mem_info) { |
| skip |= ValidateInsertAccelerationStructureMemoryRange(info.accelerationStructure, mem_info.get(), info.memoryOffset, |
| bind_info_loc.dot(Field::memoryOffset)); |
| skip |= ValidateMemoryTypes(mem_info.get(), as_state->memory_requirements.memoryTypeBits, |
| bind_info_loc.dot(Field::accelerationStructure), |
| "VUID-VkBindAccelerationStructureMemoryInfoNV-memory-03622"); |
| } |
| |
| // Validate memory requirements alignment |
| if (SafeModulo(info.memoryOffset, as_state->memory_requirements.alignment) != 0) { |
| skip |= LogError("VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-03623", info.accelerationStructure, |
| bind_info_loc.dot(Field::memoryOffset), |
| "(%" PRIu64 ") must be a multiple of the alignment (%" PRIu64 |
| ") member of the VkMemoryRequirements structure returned from " |
| "a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure %s and type of " |
| "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV", |
| info.memoryOffset, as_state->memory_requirements.alignment, |
| FormatHandle(info.accelerationStructure).c_str()); |
| } |
| |
| if (mem_info) { |
| // Validate memory requirements size |
| if (as_state->memory_requirements.size > (mem_info->alloc_info.allocationSize - info.memoryOffset)) { |
| skip |= LogError("VUID-VkBindAccelerationStructureMemoryInfoNV-size-03624", info.accelerationStructure, |
| bind_info_loc.dot(Field::memory), |
| "'s size (%" PRIu64 ") minus %s (%" PRIu64 ") is %" PRIu64 |
| ", but the size member of the VkMemoryRequirements structure returned from a call to " |
| "vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure %s and type of " |
| "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV is %" PRIu64 ".", |
| as_state->memory_requirements.size, bind_info_loc.dot(Field::memoryOffset).Fields().c_str(), |
| info.memoryOffset, mem_info->alloc_info.allocationSize - info.memoryOffset, |
| FormatHandle(info.accelerationStructure).c_str(), as_state->memory_requirements.size); |
| } |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, |
| size_t dataSize, void *pData, const ErrorObject &error_obj) const { |
| bool skip = false; |
| |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(accelerationStructure); |
| if (as_state != nullptr) { |
| skip = VerifyBoundMemoryIsValid(as_state->MemState(), LogObjectList(accelerationStructure), as_state->Handle(), |
| error_obj.location.dot(Field::accelerationStructure), |
| "VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-02787"); |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdBuildAccelerationStructuresKHR( |
| VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, |
| const VkAccelerationStructureBuildRangeInfoKHR *const *ppBuildRangeInfos, const ErrorObject &error_obj) const { |
| using sparse_container::range; |
| bool skip = false; |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| if (!pInfos || !ppBuildRangeInfos) { |
| return skip; |
| } |
| |
| for (uint32_t info_i = 0; info_i < infoCount; ++info_i) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, info_i); |
| const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_i].srcAccelerationStructure); |
| const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_i].dstAccelerationStructure); |
| |
| if (dst_as_state != nullptr) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *dst_as_state->buffer_state, |
| info_loc.dot(Field::dstAccelerationStructure), |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03707"); |
| } |
| |
| if (pInfos[info_i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) { |
| if (pInfos[info_i].srcAccelerationStructure == VK_NULL_HANDLE) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= |
| LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-04630", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR but srcAccelerationStructure is VK_NULL_HANDLE."); |
| } else if (src_as_state == nullptr || !src_as_state->built || |
| !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03667", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, srcAccelerationStructure has been previously " |
| "constructed with flags %s.", |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (src_as_state != nullptr) { |
| if (!src_as_state->buffer_state) { |
| const LogObjectList objlist(device, commandBuffer, src_as_state->Handle()); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03708", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR but the buffer associated with " |
| "srcAccelerationStructure is not valid."); |
| } else { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *src_as_state->buffer_state, |
| info_loc.dot(Field::srcAccelerationStructure), |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03708"); |
| } |
| if (pInfos[info_i].geometryCount != src_as_state->build_info_khr.geometryCount) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03758", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but geometryCount (%" PRIu32 |
| ") must have the same value which was specified when " |
| "srcAccelerationStructure was last built (%" PRIu32 ").", |
| pInfos[info_i].geometryCount, src_as_state->build_info_khr.geometryCount); |
| } |
| if (pInfos[info_i].flags != src_as_state->build_info_khr.flags) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= |
| LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03759", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, but flags (%s) must have the same value which" |
| " was specified when srcAccelerationStructure was last built (%s).", |
| string_VkBuildAccelerationStructureFlagsKHR(pInfos[info_i].flags).c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (pInfos[info_i].type != src_as_state->build_info_khr.type) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= |
| LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03760", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, but type (%s) must have the same value which" |
| " was specified when srcAccelerationStructure was last built (%s).", |
| string_VkAccelerationStructureTypeKHR(pInfos[info_i].type), |
| string_VkAccelerationStructureTypeKHR(src_as_state->build_info_khr.type)); |
| } |
| } |
| } |
| if (pInfos[info_i].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= LogError( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03700", objlist, info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, but its dstAccelerationStructure was created with %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| if (pInfos[info_i].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| const LogObjectList objlist(device, commandBuffer); |
| skip |= LogError( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03699", objlist, info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, but its dstAccelerationStructure was created with %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| |
| skip |= ValidateAccelerationBuffers(info_i, pInfos[info_i], info_loc); |
| } |
| |
| auto no_as_buffer_memory_overlap_msg = |
| [this](const char *variable_name_a, VkBuffer buffer_handle_a, const char *variable_name_b, VkBuffer buffer_handle_b, |
| VkDeviceMemory memory_handle, const range<VkDeviceSize> &overlap_range) -> std::string { |
| std::stringstream error_msg_ss; |
| error_msg_ss << "memory backing buffer (" << FormatHandle(buffer_handle_a) << ") used as storage for " << variable_name_a |
| << " overlaps memory backing buffer (" << FormatHandle(buffer_handle_b) << ") used as storage for " |
| << variable_name_b << ". Overlapped memory is " << FormatHandle(memory_handle) << " on range " |
| << string_range(overlap_range) << '.'; |
| |
| return error_msg_ss.str(); |
| }; |
| |
| auto validate_no_as_buffer_memory_overlap = |
| [this, commandBuffer, &no_as_buffer_memory_overlap_msg, error_obj]( |
| const ACCELERATION_STRUCTURE_STATE_KHR &accel_struct_a, const char *variable_name_a, const BUFFER_STATE &buffer_a, |
| const sparse_container::range<VkDeviceSize> &range_a, |
| |
| const ACCELERATION_STRUCTURE_STATE_KHR &accel_struct_b, const char *variable_name_b, const BUFFER_STATE &buffer_b, |
| const sparse_container::range<VkDeviceSize> &range_b, |
| |
| const char *vuid) { |
| bool skip = false; |
| |
| if (const auto [memory, overlap_range] = buffer_a.GetResourceMemoryOverlap(range_a, &buffer_b, range_b); |
| memory != VK_NULL_HANDLE) { |
| const LogObjectList objlist(commandBuffer, accel_struct_a.Handle(), buffer_a.Handle(), accel_struct_b.Handle(), |
| buffer_b.Handle()); |
| const std::string error_msg = no_as_buffer_memory_overlap_msg(variable_name_a, buffer_a.buffer(), variable_name_b, |
| buffer_b.buffer(), memory, overlap_range); |
| skip |= LogError(vuid, objlist, error_obj.location, "%s", error_msg.c_str()); |
| } |
| |
| return skip; |
| }; |
| |
| for (uint32_t info_i = 0; info_i < infoCount; ++info_i) { |
| const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_i].srcAccelerationStructure); |
| const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_i].dstAccelerationStructure); |
| |
| // loop over the others VkAccelerationStructureBuildGeometryInfoKHR from pInfos |
| for (uint32_t other_info_j = info_i; other_info_j < infoCount; ++other_info_j) { |
| // Validate that scratch buffer's memory does not overlap destination acceleration structure's memory, or source |
| // acceleration structure's memory if build mode is update, or other scratch buffers' memory. |
| // Here validation is pessimistic: if one buffer associated to pInfos[other_info_j].scratchData.deviceAddress has an |
| // overlap, an error will be logged. |
| // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/6040 |
| #if 0 |
| if (auto other_scratches = GetBuffersByAddress(pInfos[other_info_j].scratchData.deviceAddress); |
| !other_scratches.empty()) { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<3> other_scratches_validator; |
| |
| // Validate that scratch buffer's memory does not overlap destination acceleration structure's memory |
| if (dst_as_state && dst_as_state->buffer_state) { |
| const BUFFER_STATE &dst_as_buffer = *dst_as_state->buffer_state; |
| const range<VkDeviceSize> dst_as_buffer_range( |
| dst_as_state->create_infoKHR.offset, |
| dst_as_state->create_infoKHR.offset + dst_as_state->create_infoKHR.size); |
| |
| other_scratches_validator.AddVuidValidation( |
| {"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03703", |
| LogObjectList(commandBuffer, dst_as_state->Handle(), dst_as_buffer.Handle()), |
| // clang-format off |
| [info_i, |
| other_info_j, |
| &no_as_buffer_memory_overlap_msg, |
| &dst_as_buffer, |
| dst_as_buffer_range, |
| // Since scratch buffer size is unknown, compute an assumed scratch buffer size the idiomatic way |
| assumed_other_scratch_size = rt::ComputeScratchSize(device, pInfos[other_info_j], ppBuildRangeInfos[other_info_j]), |
| other_scratch_address = pInfos[other_info_j].scratchData.deviceAddress] |
| // clang-format on |
| (const BUFFER_STATE_PTR &other_scratch, std::string *out_error_msg) -> bool { |
| assert(other_scratch->DeviceAddressRange().includes(other_scratch_address)); |
| |
| const VkDeviceSize other_scratch_offset = other_scratch_address - other_scratch->deviceAddress; |
| const range<VkDeviceSize> other_scratch_range( |
| other_scratch_offset, |
| std::min(other_scratch_offset + assumed_other_scratch_size, other_scratch->createInfo.size)); |
| if (other_scratch_range.invalid()) { |
| // Do not validate this VU if range is invalid |
| return true; |
| } |
| |
| if (const auto [memory, overlap_range] = dst_as_buffer.GetResourceMemoryOverlap( |
| dst_as_buffer_range, other_scratch, other_scratch_range); |
| memory != VK_NULL_HANDLE) { |
| if (out_error_msg) { |
| std::stringstream dst_as_var_name_ss; |
| dst_as_var_name_ss << "pInfos[" << info_i << "].dstAccelerationStructure"; |
| std::stringstream other_scratch_var_name_ss; |
| other_scratch_var_name_ss << "pInfos[" << other_info_j << "].scratchData"; |
| |
| *out_error_msg += no_as_buffer_memory_overlap_msg( |
| dst_as_var_name_ss.str().c_str(), dst_as_buffer.buffer(), |
| other_scratch_var_name_ss.str().c_str(), other_scratch->buffer(), memory, overlap_range); |
| } |
| return false; |
| } |
| return true; |
| }, |
| [info_i, other_info_j]() { |
| return std::string("Some buffers associated to pInfos[") + std::to_string(other_info_j) + |
| "].scratchData.deviceAddress have their underlying memory overlapping with the memory " |
| "backing pInfos[" + |
| std::to_string(info_i) + "].dstAccelerationStructure.\n"; |
| }}); |
| } |
| |
| // Validate that scratch buffer's memory does not overlap source acceleration structure's memory if build mode is |
| // update |
| if (pInfos[info_i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR && src_as_state && |
| src_as_state->buffer_state) { |
| const BUFFER_STATE &src_as_buffer = *src_as_state->buffer_state; |
| const range<VkDeviceSize> src_as_buffer_range( |
| src_as_state->create_infoKHR.offset, |
| src_as_state->create_infoKHR.offset + src_as_state->create_infoKHR.size); |
| |
| other_scratches_validator.AddVuidValidation( |
| {"VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03705", |
| LogObjectList(commandBuffer, src_as_state->Handle(), src_as_buffer.Handle()), |
| // clang-format off |
| [info_i, |
| other_info_j, |
| &no_as_buffer_memory_overlap_msg, |
| &src_as_buffer, |
| src_as_buffer_range, |
| // Since scratch buffer size is unknown, compute an assumed scratch buffer size the idiomatic way |
| assumed_other_scratch_size = rt::ComputeScratchSize(device, pInfos[other_info_j], ppBuildRangeInfos[other_info_j]), |
| other_scratch_address = pInfos[other_info_j].scratchData.deviceAddress] |
| // clang-format on |
| (const BUFFER_STATE_PTR &other_scratch, std::string *out_error_msg) -> bool { |
| assert(other_scratch->DeviceAddressRange().includes(other_scratch_address)); |
| |
| const VkDeviceSize other_scratch_offset = other_scratch_address - other_scratch->deviceAddress; |
| const range<VkDeviceSize> other_scratch_range( |
| other_scratch_offset, |
| std::min(other_scratch_offset + assumed_other_scratch_size, other_scratch->createInfo.size)); |
| if (other_scratch_range.invalid()) { |
| // Do not validate this VU if range is invalid |
| return true; |
| } |
| |
| if (const auto [memory, overlap_range] = src_as_buffer.GetResourceMemoryOverlap( |
| src_as_buffer_range, other_scratch, other_scratch_range); |
| memory != VK_NULL_HANDLE) { |
| if (out_error_msg) { |
| std::stringstream src_as_var_name_ss; |
| src_as_var_name_ss << "pInfos[" << info_i << "].srcAccelerationStructure"; |
| std::stringstream other_scratch_var_name_ss; |
| other_scratch_var_name_ss << "pInfos[" << other_info_j << "].scratchData"; |
| |
| *out_error_msg += no_as_buffer_memory_overlap_msg( |
| src_as_var_name_ss.str().c_str(), src_as_buffer.buffer(), |
| other_scratch_var_name_ss.str().c_str(), other_scratch->buffer(), memory, overlap_range); |
| } |
| return false; |
| } |
| return true; |
| }, |
| [info_i, other_info_j]() { |
| return std::string("Some buffers associated to pInfos[") + std::to_string(other_info_j) + |
| "].scratchData.deviceAddress have their underlying memory overlapping with the memory " |
| "backing pInfos[" + |
| std::to_string(info_i) + "].srcAccelerationStructure:\n"; |
| }}); |
| } |
| |
| // Validate that scratch buffers' memory do not overlap. |
| // Since pInfos[info_i].scratchData.deviceAddress can point to multiple buffers, |
| // `other_scratch` needs to be validated against all of these buffers: if one pair has their respective memory |
| // overlapping, validation failed |
| auto scratches = GetBuffersByAddress(pInfos[info_i].scratchData.deviceAddress); |
| if (info_i != other_info_j) { |
| if (!scratches.empty()) { |
| other_scratches_validator.AddVuidValidation( |
| {"VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704", LogObjectList(commandBuffer), |
| // clang-format off |
| [this, |
| commandBuffer, |
| info_i, |
| scratch_address = pInfos[info_i].scratchData.deviceAddress, |
| assumed_scratch_size = rt::ComputeScratchSize(device, pInfos[info_i], ppBuildRangeInfos[info_i]), |
| &scratches, |
| other_scratch_address = pInfos[other_info_j].scratchData.deviceAddress, |
| assumed_other_scratch_size = rt::ComputeScratchSize(device, pInfos[other_info_j], ppBuildRangeInfos[other_info_j])] |
| // clang-format on |
| (const BUFFER_STATE_PTR &other_scratch, std::string *out_error_msg) -> bool { |
| assert(other_scratch->DeviceAddressRange().includes(other_scratch_address)); |
| |
| const VkDeviceSize other_scratch_offset = other_scratch_address - other_scratch->deviceAddress; |
| const range<VkDeviceSize> other_scratch_range( |
| other_scratch_offset, |
| std::min(other_scratch_offset + assumed_other_scratch_size, other_scratch->createInfo.size)); |
| if (other_scratch_range.invalid()) { |
| // Do not validate this VU if range is invalid |
| return true; |
| } |
| |
| // Create a nested BufferAddressValidation object, this time to loop over buffers associated to |
| // pInfos[info_i].scratchData.deviceAddress |
| // If one does overlap "other_scratch", then validation of 03704 failed |
| BufferAddressValidation<1> scratch_and_other_scratch_overlap_validator = { |
| {{{"No-VUID", LogObjectList(commandBuffer), |
| // clang-format off |
| [this, |
| scratch_address, |
| assumed_scratch_size, |
| &other_scratch, |
| other_scratch_range, |
| parent_out_error_msg = out_error_msg] |
| // clang-format on |
| (const BUFFER_STATE_PTR &scratch, std::string *) -> bool { |
| const VkDeviceSize scratch_offset = scratch_address - scratch->deviceAddress; |
| const range<VkDeviceSize> scratch_range( |
| scratch_offset, |
| std::min(scratch_offset + assumed_scratch_size, scratch->createInfo.size)); |
| |
| // Do not validate this VU if range is invalid |
| if (scratch_range.invalid()) { |
| return true; |
| } |
| |
| if (const auto [memory, overlap_range] = scratch->GetResourceMemoryOverlap( |
| scratch_range, other_scratch, other_scratch_range); |
| memory != VK_NULL_HANDLE) { |
| if (parent_out_error_msg) { |
| std::stringstream scratch_error_msg_ss; |
| scratch_error_msg_ss << " {" << FormatHandle(scratch->buffer()) |
| << ", backed by " << FormatHandle(memory) |
| << " - overlap on VkDeviceMemory space range " |
| << string_range(overlap_range) << "}"; |
| *parent_out_error_msg += scratch_error_msg_ss.str(); |
| } |
| return false; |
| } |
| return true; |
| }}}}}; |
| |
| if (!out_error_msg) { |
| return !scratch_and_other_scratch_overlap_validator.HasInvalidBuffer(scratches); |
| } else { |
| const std::string address_name = [&]() { |
| std::stringstream address_name_ss; |
| address_name_ss << "pInfos[" << info_i << "].scratchData.deviceAddress"; |
| return address_name_ss.str(); |
| }(); |
| *out_error_msg += |
| "Memory backing this buffer is overlapped by memory backing the following buffer(s) " |
| "associated to "; |
| *out_error_msg += address_name; |
| *out_error_msg += ':'; |
| // Buffer from the `scratches` list overlapping `other_scratch` will be |
| // appended in out_error_msg in the LogInvalidBuffers call |
| return scratch_and_other_scratch_overlap_validator.LogInvalidBuffers( |
| *this, scratches, "vkCmdBuildAccelerationStructures", address_name.c_str(), |
| scratch_address); |
| } |
| }, |
| [info_i]() { |
| return std::string( |
| "The following buffers have their underlying memory overlapping buffers " |
| "associated to pInfos[") + |
| std::to_string(info_i) + "].scratchData.deviceAddress:\n"; |
| }}); |
| } |
| } |
| |
| std::stringstream address_name_ss; |
| address_name_ss << "pInfos[" << other_info_j << "].scratchData.deviceAddress"; |
| |
| skip |= other_scratches_validator.LogErrorsIfInvalidBufferFound( |
| *this, other_scratches, "vkCmdBuildAccelerationStructuresKHR()", address_name_ss.str(), |
| pInfos[other_info_j].scratchData.deviceAddress); |
| } |
| #endif |
| // skip comparing to self pInfos[info_i] |
| if (other_info_j != info_i) { |
| const auto other_dst_as_state = |
| Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[other_info_j].dstAccelerationStructure); |
| const auto other_src_as_state = |
| Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[other_info_j].srcAccelerationStructure); |
| |
| // Validate destination acceleration structure's memory is not overlapped by another source acceleration structure's |
| // memory that is going to be updated by this cmd |
| if (dst_as_state && dst_as_state->buffer_state && other_src_as_state && other_src_as_state->buffer_state) { |
| if (pInfos[other_info_j].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) { |
| std::stringstream dst_as_ss; |
| dst_as_ss << "pInfos[" << info_i << "].dstAccelerationStructure (" |
| << FormatHandle(pInfos[info_i].dstAccelerationStructure) << ')'; |
| std::stringstream other_src_as_ss; |
| other_src_as_ss << "pInfos[" << other_info_j << "].srcAccelerationStructure (" |
| << FormatHandle(pInfos[other_info_j].srcAccelerationStructure) << ')'; |
| |
| const BUFFER_STATE &buffer_a = *dst_as_state->buffer_state; |
| const range<VkDeviceSize> range_a(dst_as_state->create_infoKHR.offset, |
| dst_as_state->create_infoKHR.offset + dst_as_state->create_infoKHR.size); |
| |
| const BUFFER_STATE &buffer_b = *other_src_as_state->buffer_state; |
| const range<VkDeviceSize> range_b( |
| other_src_as_state->create_infoKHR.offset, |
| other_src_as_state->create_infoKHR.offset + other_src_as_state->create_infoKHR.size); |
| |
| skip |= validate_no_as_buffer_memory_overlap( |
| *dst_as_state, dst_as_ss.str().c_str(), buffer_a, range_a, *other_src_as_state, |
| other_src_as_ss.str().c_str(), buffer_b, range_b, |
| "VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03701"); |
| } |
| } |
| |
| // Validate that there is no destination acceleration structures' memory overlaps |
| if (dst_as_state && dst_as_state->buffer_state && other_dst_as_state && other_dst_as_state->buffer_state) { |
| std::stringstream dst_as_ss; |
| dst_as_ss << "pInfos[" << info_i << "].dstAccelerationStructure (" |
| << FormatHandle(pInfos[info_i].dstAccelerationStructure) << ')'; |
| std::stringstream other_dst_as_ss; |
| other_dst_as_ss << "pInfos[" << other_info_j << "].dstAccelerationStructure (" |
| << FormatHandle(pInfos[other_info_j].dstAccelerationStructure) << ')'; |
| |
| const BUFFER_STATE &buffer_a = *dst_as_state->buffer_state; |
| const range<VkDeviceSize> range_a(dst_as_state->create_infoKHR.offset, |
| dst_as_state->create_infoKHR.offset + dst_as_state->create_infoKHR.size); |
| |
| const BUFFER_STATE &buffer_b = *other_dst_as_state->buffer_state; |
| const range<VkDeviceSize> range_b( |
| other_dst_as_state->create_infoKHR.offset, |
| other_dst_as_state->create_infoKHR.offset + other_dst_as_state->create_infoKHR.size); |
| |
| skip |= validate_no_as_buffer_memory_overlap( |
| *dst_as_state, dst_as_ss.str().c_str(), buffer_a, range_a, *other_dst_as_state, |
| other_dst_as_ss.str().c_str(), buffer_b, range_b, |
| "VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702"); |
| } |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateAccelerationBuffers(uint32_t info_index, const VkAccelerationStructureBuildGeometryInfoKHR &info, |
| const Location &loc) const { |
| bool skip = false; |
| const auto geometry_count = info.geometryCount; |
| const auto *p_geometries = info.pGeometries; |
| const auto *const *const pp_geometries = info.ppGeometries; |
| |
| auto buffer_check = [this](uint32_t gi, const VkDeviceOrHostAddressConstKHR address, const Location &geom_loc) -> bool { |
| const auto buffer_states = GetBuffersByAddress(address.deviceAddress); |
| const bool no_valid_buffer_found = |
| !buffer_states.empty() && |
| std::none_of(buffer_states.begin(), buffer_states.end(), |
| [](const ValidationStateTracker::BUFFER_STATE_PTR &buffer_state) { |
| return buffer_state->usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; |
| }); |
| if (no_valid_buffer_found) { |
| LogObjectList objlist(device); |
| for (const auto &buffer_state : buffer_states) { |
| objlist.add(buffer_state->Handle()); |
| } |
| return LogError( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673", objlist, geom_loc, |
| "has no buffer which created with VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR."); |
| } |
| |
| return false; |
| }; |
| |
| // Parameter validation has already checked VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788 |
| // !(pGeometries && ppGeometries) |
| std::function<const VkAccelerationStructureGeometryKHR &(uint32_t)> geom_accessor; |
| if (p_geometries) { |
| geom_accessor = [p_geometries](uint32_t i) -> const VkAccelerationStructureGeometryKHR & { return p_geometries[i]; }; |
| } else if (pp_geometries) { |
| geom_accessor = [pp_geometries](uint32_t i) -> const VkAccelerationStructureGeometryKHR & { |
| // pp_geometries[i] is assumed to be a valid pointer |
| return *pp_geometries[i]; |
| }; |
| } |
| |
| if (geom_accessor) { |
| for (uint32_t geom_index = 0; geom_index < geometry_count; ++geom_index) { |
| const Location geom_loc = loc.dot(Field::pGeometries, geom_index); |
| const auto &geom_data = geom_accessor(geom_index); |
| switch (geom_data.geometryType) { |
| case VK_GEOMETRY_TYPE_TRIANGLES_KHR: // == VK_GEOMETRY_TYPE_TRIANGLES_NV |
| skip |= buffer_check(geom_index, geom_data.geometry.triangles.vertexData, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::vertexData)); |
| skip |= buffer_check(geom_index, geom_data.geometry.triangles.indexData, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::indexData)); |
| skip |= buffer_check(geom_index, geom_data.geometry.triangles.transformData, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::transformData)); |
| break; |
| case VK_GEOMETRY_TYPE_INSTANCES_KHR: |
| skip |= buffer_check(geom_index, geom_data.geometry.instances.data, |
| geom_loc.dot(Field::geometry).dot(Field::instances).dot(Field::data)); |
| break; |
| case VK_GEOMETRY_TYPE_AABBS_KHR: // == VK_GEOMETRY_TYPE_AABBS_NV |
| skip |= buffer_check(geom_index, geom_data.geometry.aabbs.data, |
| geom_loc.dot(Field::geometry).dot(Field::aabbs).dot(Field::data)); |
| break; |
| default: |
| // no-op |
| break; |
| } |
| } |
| } |
| |
| const auto buffer_states = GetBuffersByAddress(info.scratchData.deviceAddress); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03802", device, |
| loc.dot(Field::scratchData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") has no buffer is associated with it.", info.scratchData.deviceAddress); |
| } else { |
| const bool no_valid_buffer_found = std::none_of(buffer_states.begin(), buffer_states.end(), |
| [](const ValidationStateTracker::BUFFER_STATE_PTR &buffer_state) { |
| return buffer_state->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| }); |
| if (no_valid_buffer_found) { |
| LogObjectList objlist(device); |
| for (const auto &buffer_state : buffer_states) { |
| objlist.add(buffer_state->Handle()); |
| } |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674", objlist, |
| loc.dot(Field::scratchData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 |
| ") has no buffer is associated with it that was created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT bit.", |
| info.scratchData.deviceAddress); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateBuildAccelerationStructuresKHR( |
| VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, |
| const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, |
| const VkAccelerationStructureBuildRangeInfoKHR *const *ppBuildRangeInfos, const ErrorObject &error_obj) const { |
| bool skip = false; |
| for (uint32_t i = 0; i < infoCount; ++i) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, i); |
| auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].srcAccelerationStructure); |
| auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].dstAccelerationStructure); |
| if (dst_as_state) { |
| skip |= |
| ValidateHostVisibleMemoryIsBoundToBuffer(*dst_as_state->buffer_state, info_loc.dot(Field::dstAccelerationStructure), |
| "VUID-vkBuildAccelerationStructuresKHR-pInfos-03722"); |
| } |
| if (pInfos[i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) { |
| if (src_as_state == nullptr || !src_as_state->built || |
| !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) { |
| skip |= LogError( |
| "VUID-vkBuildAccelerationStructuresKHR-pInfos-03667", pInfos[i].srcAccelerationStructure, |
| info_loc.dot(Field::mode), |
| "is " |
| "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, but its srcAccelerationStructure was built before with %s.", |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (src_as_state) { |
| skip |= ValidateHostVisibleMemoryIsBoundToBuffer(*src_as_state->buffer_state, |
| info_loc.dot(Field::srcAccelerationStructure), |
| "VUID-vkBuildAccelerationStructuresKHR-pInfos-03723"); |
| if (pInfos[i].geometryCount != src_as_state->build_info_khr.geometryCount) { |
| skip |= |
| LogError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03758", pInfos[i].srcAccelerationStructure, |
| info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but geometryCount (%" PRIu32 ") is different then srcAccelerationStructure value (%" PRIu32 ").", |
| pInfos[i].geometryCount, src_as_state->build_info_khr.geometryCount); |
| } |
| if (pInfos[i].flags != src_as_state->build_info_khr.flags) { |
| skip |= LogError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03759", pInfos[i].srcAccelerationStructure, |
| info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but flags (%s) is different then srcAccelerationStructure value (%s).", |
| string_VkBuildAccelerationStructureFlagsKHR(pInfos[i].flags).c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (pInfos[i].type != src_as_state->build_info_khr.type) { |
| skip |= LogError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03760", pInfos[i].srcAccelerationStructure, |
| info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but type (%s) is different then srcAccelerationStructure value (%s).", |
| string_VkAccelerationStructureTypeKHR(pInfos[i].type), |
| string_VkAccelerationStructureTypeKHR(src_as_state->build_info_khr.type)); |
| } |
| } |
| } |
| if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| skip |= LogError( |
| "VUID-vkBuildAccelerationStructuresKHR-pInfos-03700", pInfos[i].dstAccelerationStructure, |
| info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, but its dstAccelerationStructure was built with type %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| skip |= LogError( |
| "VUID-vkBuildAccelerationStructuresKHR-pInfos-03699", pInfos[i].dstAccelerationStructure, |
| info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, but its dstAccelerationStructure was built with type %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| } |
| return skip; |
| } |
| bool CoreChecks::PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, |
| const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData, |
| VkDeviceSize instanceOffset, VkBool32 update, |
| VkAccelerationStructureNV dst, VkAccelerationStructureNV src, |
| VkBuffer scratch, VkDeviceSize scratchOffset, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| if (pInfo != nullptr && pInfo->type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV) { |
| for (uint32_t i = 0; i < pInfo->geometryCount; i++) { |
| skip |= ValidateGeometryNV(pInfo->pGeometries[i], error_obj.location.dot(Field::pInfo).dot(Field::pGeometries, i)); |
| } |
| } |
| |
| if (pInfo != nullptr && pInfo->geometryCount > phys_dev_ext_props.ray_tracing_props_nv.maxGeometryCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-geometryCount-02241", commandBuffer, error_obj.location, |
| "geometryCount [%" PRIu32 |
| "] must be less than or equal to " |
| "VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount.", |
| pInfo->geometryCount); |
| } |
| |
| auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(dst); |
| auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(src); |
| auto scratch_buffer_state = Get<BUFFER_STATE>(scratch); |
| |
| if (dst_as_state != nullptr && pInfo != nullptr) { |
| if (dst_as_state->create_infoNV.info.type != pInfo->type) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info VkAccelerationStructureInfoNV::type" |
| "[%s] must be identical to build info VkAccelerationStructureInfoNV::type [%s].", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoNV.info.type), |
| string_VkAccelerationStructureTypeKHR(pInfo->type)); |
| } |
| if (dst_as_state->create_infoNV.info.flags != pInfo->flags) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info VkAccelerationStructureInfoNV::flags" |
| "[0x%x] must be identical to build info VkAccelerationStructureInfoNV::flags [0x%x].", |
| dst_as_state->create_infoNV.info.flags, pInfo->flags); |
| } |
| if (dst_as_state->create_infoNV.info.instanceCount < pInfo->instanceCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info VkAccelerationStructureInfoNV::instanceCount " |
| "[%" PRIu32 |
| "] must be greater than or equal to build info VkAccelerationStructureInfoNV::instanceCount [%" PRIu32 |
| "].", |
| dst_as_state->create_infoNV.info.instanceCount, pInfo->instanceCount); |
| } |
| if (dst_as_state->create_infoNV.info.geometryCount < pInfo->geometryCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info VkAccelerationStructureInfoNV::geometryCount" |
| "[%" PRIu32 |
| "] must be greater than or equal to build info VkAccelerationStructureInfoNV::geometryCount [%" PRIu32 |
| "].", |
| dst_as_state->create_infoNV.info.geometryCount, pInfo->geometryCount); |
| } else { |
| for (uint32_t i = 0; i < pInfo->geometryCount; i++) { |
| const VkGeometryDataNV &create_geometry_data = dst_as_state->create_infoNV.info.pGeometries[i].geometry; |
| const VkGeometryDataNV &build_geometry_data = pInfo->pGeometries[i].geometry; |
| if (create_geometry_data.triangles.vertexCount < build_geometry_data.triangles.vertexCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info pGeometries[%" PRIu32 "].geometry.triangles.vertexCount [%" PRIu32 |
| "]" |
| "must be greater than or equal to build info pGeometries[%" PRIu32 |
| "].geometry.triangles.vertexCount [%" PRIu32 "].", |
| i, create_geometry_data.triangles.vertexCount, i, build_geometry_data.triangles.vertexCount); |
| break; |
| } |
| if (create_geometry_data.triangles.indexCount < build_geometry_data.triangles.indexCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info pGeometries[%" PRIu32 "].geometry.triangles.indexCount [%" PRIu32 |
| "]" |
| "must be greater than or equal to build info pGeometries[%" PRIu32 |
| "].geometry.triangles.indexCount [%" PRIu32 "].", |
| i, create_geometry_data.triangles.indexCount, i, build_geometry_data.triangles.indexCount); |
| break; |
| } |
| if (create_geometry_data.aabbs.numAABBs < build_geometry_data.aabbs.numAABBs) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488", commandBuffer, error_obj.location, |
| "create info pGeometries[%" PRIu32 "].geometry.aabbs.numAABBs [%" PRIu32 |
| "]" |
| "must be greater than or equal to build info pGeometries[%" PRIu32 |
| "].geometry.aabbs.numAABBs [%" PRIu32 "].", |
| i, create_geometry_data.aabbs.numAABBs, i, build_geometry_data.aabbs.numAABBs); |
| break; |
| } |
| } |
| } |
| } |
| |
| if (dst_as_state != nullptr) { |
| skip |= VerifyBoundMemoryIsValid(dst_as_state->MemState(), LogObjectList(commandBuffer, dst), dst_as_state->Handle(), |
| error_obj.location.dot(Field::dst), "VUID-vkCmdBuildAccelerationStructureNV-dst-07787"); |
| } |
| |
| if (update == VK_TRUE) { |
| if (src == VK_NULL_HANDLE) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-update-02489", commandBuffer, error_obj.location, |
| "If update is VK_TRUE, src must not be VK_NULL_HANDLE."); |
| } else { |
| if (src_as_state == nullptr || !src_as_state->built || |
| !(src_as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV)) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-update-02490", commandBuffer, error_obj.location, |
| "If update is VK_TRUE, src must have been built before " |
| "with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV set in " |
| "VkAccelerationStructureInfoNV::flags."); |
| } |
| } |
| if (dst_as_state != nullptr && !dst_as_state->update_scratch_memory_requirements_checked) { |
| skip |= LogWarning(kVUID_Core_CmdBuildAccelNV_NoUpdateMemReqQuery, dst, error_obj.location, |
| "Updating %s but vkGetAccelerationStructureMemoryRequirementsNV() " |
| "has not been called for update scratch memory.", |
| FormatHandle(dst_as_state->acceleration_structure()).c_str()); |
| // Use requirements fetched at create time |
| } |
| if (scratch_buffer_state != nullptr && dst_as_state != nullptr && |
| dst_as_state->update_scratch_memory_requirements.size > (scratch_buffer_state->createInfo.size - scratchOffset)) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-update-02492", commandBuffer, error_obj.location, |
| "If update is VK_TRUE, The size member of the " |
| "VkMemoryRequirements structure returned from a call to " |
| "vkGetAccelerationStructureMemoryRequirementsNV with " |
| "VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and " |
| "VkAccelerationStructureMemoryRequirementsInfoNV::type set to " |
| "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV must be less than " |
| "or equal to the size of scratch minus scratchOffset"); |
| } |
| } else { |
| if (dst_as_state != nullptr && !dst_as_state->build_scratch_memory_requirements_checked) { |
| skip |= LogWarning(kVUID_Core_CmdBuildAccelNV_NoScratchMemReqQuery, dst, error_obj.location, |
| "Assigning scratch buffer to %s but " |
| "vkGetAccelerationStructureMemoryRequirementsNV() has not been called for scratch memory.", |
| FormatHandle(dst_as_state->acceleration_structure()).c_str()); |
| // Use requirements fetched at create time |
| } |
| if (scratch_buffer_state != nullptr && dst_as_state != nullptr && |
| dst_as_state->build_scratch_memory_requirements.size > (scratch_buffer_state->createInfo.size - scratchOffset)) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructureNV-update-02491", commandBuffer, error_obj.location, |
| "If update is VK_FALSE, The size member of the " |
| "VkMemoryRequirements structure returned from a call to " |
| "vkGetAccelerationStructureMemoryRequirementsNV with " |
| "VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and " |
| "VkAccelerationStructureMemoryRequirementsInfoNV::type set to " |
| "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV must be less than " |
| "or equal to the size of scratch minus scratchOffset"); |
| } |
| } |
| if (instanceData != VK_NULL_HANDLE) { |
| auto buffer_state = Get<BUFFER_STATE>(instanceData); |
| if (buffer_state) { |
| skip |= ValidateBufferUsageFlags( |
| LogObjectList(commandBuffer, instanceData), *buffer_state, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, true, |
| "VUID-VkAccelerationStructureInfoNV-instanceData-02782", error_obj.location.dot(Field::instanceData)); |
| } |
| } |
| if (scratch_buffer_state) { |
| skip |= ValidateBufferUsageFlags( |
| LogObjectList(commandBuffer, scratch), *scratch_buffer_state, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, true, |
| "VUID-VkAccelerationStructureInfoNV-scratch-02781", error_obj.location.dot(Field::scratch)); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, |
| VkAccelerationStructureNV src, |
| VkCopyAccelerationStructureModeNV mode, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(dst); |
| auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(src); |
| |
| if (dst_as_state != nullptr) { |
| const LogObjectList objlist(commandBuffer, dst); |
| skip |= VerifyBoundMemoryIsValid(dst_as_state->MemState(), objlist, dst_as_state->Handle(), |
| error_obj.location.dot(Field::dst), "VUID-vkCmdCopyAccelerationStructureNV-dst-07792"); |
| skip |= VerifyBoundMemoryIsDeviceVisible(dst_as_state->MemState(), objlist, dst_as_state->Handle(), |
| error_obj.location.dot(Field::dst), |
| "VUID-vkCmdCopyAccelerationStructureNV-buffer-03719"); |
| } |
| if (src_as_state != nullptr) { |
| const LogObjectList objlist(commandBuffer, src); |
| skip |= VerifyBoundMemoryIsDeviceVisible(src_as_state->MemState(), objlist, src_as_state->Handle(), |
| error_obj.location.dot(Field::src), |
| "VUID-vkCmdCopyAccelerationStructureNV-buffer-03718"); |
| if (!src_as_state->built) { |
| skip |= LogError("VUID-vkCmdCopyAccelerationStructureNV-src-04963", commandBuffer, error_obj.location, |
| "The source acceleration structure src has not yet been built."); |
| } |
| } |
| |
| if (mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV) { |
| if (src_as_state != nullptr && |
| (!src_as_state->built || !(src_as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV))) { |
| skip |= LogError("VUID-vkCmdCopyAccelerationStructureNV-src-03411", commandBuffer, error_obj.location, |
| "src must have been built with " |
| "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV if mode is " |
| "VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV."); |
| } |
| } |
| if (!(mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV || mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR)) { |
| skip |= LogError("VUID-vkCmdCopyAccelerationStructureNV-mode-03410", commandBuffer, error_obj.location, |
| "mode must be VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR" |
| "or VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR."); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, |
| const VkAllocationCallbacks *pAllocator, |
| const ErrorObject &error_obj) const { |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(accelerationStructure); |
| bool skip = false; |
| if (as_state) { |
| skip |= ValidateObjectNotInUse(as_state.get(), error_obj.location, |
| "VUID-vkDestroyAccelerationStructureNV-accelerationStructure-03752"); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure, |
| const VkAllocationCallbacks *pAllocator, |
| const ErrorObject &error_obj) const { |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(accelerationStructure); |
| bool skip = false; |
| if (as_state) { |
| skip |= ValidateObjectNotInUse(as_state.get(), error_obj.location, |
| "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02442"); |
| } |
| return skip; |
| } |
| |
| void CoreChecks::PreCallRecordCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer, |
| uint32_t accelerationStructureCount, |
| const VkAccelerationStructureKHR *pAccelerationStructures, |
| VkQueryType queryType, VkQueryPool queryPool, |
| uint32_t firstQuery) { |
| if (disabled[query_validation]) return; |
| // Enqueue the submit time validation check here, before the submit time state update in StateTracker::PostCall... |
| auto cb_state = GetWrite<CMD_BUFFER_STATE>(commandBuffer); |
| cb_state->queryUpdates.emplace_back([accelerationStructureCount, firstQuery, queryPool]( |
| CMD_BUFFER_STATE &cb_state_arg, bool do_validate, VkQueryPool &firstPerfQueryPool, |
| uint32_t perfPass, QueryMap *localQueryToStateMap) { |
| if (!do_validate) return false; |
| bool skip = false; |
| for (uint32_t i = 0; i < accelerationStructureCount; i++) { |
| QueryObject query_obj = {queryPool, firstQuery + i, perfPass}; |
| skip |= VerifyQueryIsReset(cb_state_arg, query_obj, Func::vkCmdWriteAccelerationStructuresPropertiesKHR, |
| firstPerfQueryPool, perfPass, localQueryToStateMap); |
| } |
| return skip; |
| }); |
| } |
| |
| bool CoreChecks::PreCallValidateWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint32_t accelerationStructureCount, |
| const VkAccelerationStructureKHR *pAccelerationStructures, |
| VkQueryType queryType, size_t dataSize, void *pData, |
| size_t stride, const ErrorObject &error_obj) const { |
| bool skip = false; |
| for (uint32_t i = 0; i < accelerationStructureCount; ++i) { |
| const Location as_loc = error_obj.location.dot(Field::pAccelerationStructures, i); |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pAccelerationStructures[i]); |
| const auto &as_info = as_state->build_info_khr; |
| if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR) { |
| if (!(as_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) { |
| const LogObjectList objlist(device, pAccelerationStructures[i]); |
| skip |= LogError("VUID-vkWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431", objlist, as_loc, |
| "has flags %s.", string_VkBuildAccelerationStructureFlagsKHR(as_info.flags).c_str()); |
| } |
| } |
| if (as_state) { |
| skip |= ValidateHostVisibleMemoryIsBoundToBuffer(*as_state->buffer_state, as_loc, |
| "VUID-vkWriteAccelerationStructuresPropertiesKHR-buffer-03733"); |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdWriteAccelerationStructuresPropertiesKHR( |
| VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, |
| VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery, const ErrorObject &error_obj) const { |
| bool skip = false; |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool); |
| const auto &query_pool_ci = query_pool_state->createInfo; |
| if (query_pool_ci.queryType != queryType) { |
| skip |= LogError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryPool-02493", commandBuffer, |
| error_obj.location.dot(Field::queryType), |
| "was created with %s which is differnent from the type queryPool was created with %s.", |
| string_VkQueryType(queryType), string_VkQueryType(query_pool_ci.queryType)); |
| } |
| for (uint32_t i = 0; i < accelerationStructureCount; ++i) { |
| if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR) { |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pAccelerationStructures[i]); |
| if (!(as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) { |
| skip |= LogError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431", commandBuffer, |
| error_obj.location.dot(Field::pAccelerationStructures, i), |
| "was built with %s, but queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR.", |
| string_VkBuildAccelerationStructureFlagsKHR(as_state->build_info_khr.flags).c_str()); |
| } |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdWriteAccelerationStructuresPropertiesNV( |
| VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV *pAccelerationStructures, |
| VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery, const ErrorObject &error_obj) const { |
| bool skip = false; |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool); |
| const auto &query_pool_ci = query_pool_state->createInfo; |
| if (query_pool_ci.queryType != queryType) { |
| skip |= LogError("VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-03755", commandBuffer, |
| error_obj.location.dot(Field::queryType), |
| "was created with %s which is differnent from the type queryPool was created with %s.", |
| string_VkQueryType(queryType), string_VkQueryType(query_pool_ci.queryType)); |
| } |
| for (uint32_t i = 0; i < accelerationStructureCount; ++i) { |
| if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV) { |
| auto as_state = Get<ACCELERATION_STRUCTURE_STATE_NV>(pAccelerationStructures[i]); |
| if (!(as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) { |
| skip |= LogError("VUID-vkCmdWriteAccelerationStructuresPropertiesNV-pAccelerationStructures-06215", commandBuffer, |
| error_obj.location.dot(Field::pAccelerationStructures, i), |
| "was built with %s, but queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR.", |
| string_VkBuildAccelerationStructureFlagsKHR(as_state->build_info.flags).c_str()); |
| } |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, |
| const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, |
| const VkDeviceAddress *pIndirectDeviceAddresses, |
| const uint32_t *pIndirectStrides, |
| const uint32_t *const *ppMaxPrimitiveCounts, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| // TODO - This is not called in vkCmdBuildAccelerationStructuresKHR and only seems used for ValidateActionState |
| skip |= ValidateCmdRayQueryState(*cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, error_obj.location); |
| for (uint32_t i = 0; i < infoCount; ++i) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, i); |
| auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].srcAccelerationStructure); |
| auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].dstAccelerationStructure); |
| skip |= |
| ValidateMemoryIsBoundToBuffer(commandBuffer, *dst_as_state->buffer_state, info_loc.dot(Field::dstAccelerationStructure), |
| "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03707"); |
| if (pInfos[i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *src_as_state->buffer_state, |
| info_loc.dot(Field::srcAccelerationStructure), |
| "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03708"); |
| if (src_as_state == nullptr || !src_as_state->built || |
| !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03667", |
| pInfos[i].srcAccelerationStructure, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but srcAccelerationStructure was created with (%s)", |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (pInfos[i].geometryCount != src_as_state->build_info_khr.geometryCount) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03758", |
| pInfos[i].srcAccelerationStructure, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but geometryCount (%" PRIu32 ") is different then srcAccelerationStructure value (%" PRIu32 ").", |
| pInfos[i].geometryCount, src_as_state->build_info_khr.geometryCount); |
| } |
| if (pInfos[i].flags != src_as_state->build_info_khr.flags) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03759", |
| pInfos[i].srcAccelerationStructure, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but flags (%s) is different than srcAccelerationStructure value (%s).", |
| string_VkBuildAccelerationStructureFlagsKHR(pInfos[i].flags).c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (pInfos[i].type != src_as_state->build_info_khr.type) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03760", |
| pInfos[i].srcAccelerationStructure, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR," |
| " but type (%s) is different than srcAccelerationStructure value (%s).", |
| string_VkAccelerationStructureTypeKHR(pInfos[i].type), |
| string_VkAccelerationStructureTypeKHR(src_as_state->build_info_khr.type)); |
| } |
| } |
| if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| skip |= LogError( |
| "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03700", pInfos[i].dstAccelerationStructure, |
| info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, but its dstAccelerationStructure was built with type %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) { |
| if (!dst_as_state || |
| (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR && |
| dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) { |
| skip |= LogError( |
| "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03699", pInfos[i].dstAccelerationStructure, |
| info_loc.dot(Field::type), |
| "is VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, but its dstAccelerationStructure was built with type %s.", |
| string_VkAccelerationStructureTypeKHR(dst_as_state->create_infoKHR.type)); |
| } |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateCopyAccelerationStructureInfoKHR(const VkCopyAccelerationStructureInfoKHR *pInfo, |
| const VulkanTypedHandle &handle, const Location &info_loc) const { |
| bool skip = false; |
| if (pInfo->mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR) { |
| auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src); |
| if (!(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) { |
| const LogObjectList objlist(handle, pInfo->src); |
| skip |= LogError("VUID-VkCopyAccelerationStructureInfoKHR-src-03411", objlist, info_loc.dot(Field::src), |
| "(%s) must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR" |
| "if mode is VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR.", |
| FormatHandle(pInfo->src).c_str()); |
| } |
| } |
| auto src_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src); |
| if (src_accel_state) { |
| auto buffer_state = Get<BUFFER_STATE>(src_accel_state->create_infoKHR.buffer); |
| skip |= ValidateMemoryIsBoundToBuffer(device, *buffer_state, info_loc.dot(Field::src), |
| "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718"); |
| } |
| auto dst_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst); |
| if (dst_accel_state) { |
| auto buffer_state = Get<BUFFER_STATE>(dst_accel_state->create_infoKHR.buffer); |
| skip |= ValidateMemoryIsBoundToBuffer(device, *buffer_state, info_loc.dot(Field::dst), |
| "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719"); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer, |
| const VkCopyAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| if (pInfo) { |
| const Location info_loc = error_obj.location.dot(Field::pInfo); |
| skip |= ValidateCopyAccelerationStructureInfoKHR(pInfo, error_obj.handle, info_loc); |
| auto src_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src); |
| if (src_accel_state) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *src_accel_state->buffer_state, info_loc.dot(Field::src), |
| "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03737"); |
| } |
| auto dst_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst); |
| if (dst_accel_state) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *dst_accel_state->buffer_state, info_loc.dot(Field::dst), |
| "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03738"); |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, |
| const VkCopyAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| if (pInfo) { |
| const Location info_loc = error_obj.location.dot(Field::pInfo); |
| skip |= ValidateCopyAccelerationStructureInfoKHR(pInfo, error_obj.handle, error_obj.location.dot(Field::pInfo)); |
| auto src_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src); |
| if (src_accel_state) { |
| skip |= ValidateHostVisibleMemoryIsBoundToBuffer(*src_accel_state->buffer_state, info_loc.dot(Field::src), |
| "VUID-vkCopyAccelerationStructureKHR-buffer-03727"); |
| } |
| auto dst_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst); |
| if (dst_accel_state) { |
| skip |= ValidateHostVisibleMemoryIsBoundToBuffer(*dst_accel_state->buffer_state, info_loc.dot(Field::dst), |
| "VUID-vkCopyAccelerationStructureKHR-buffer-03728"); |
| } |
| } |
| return skip; |
| } |
| bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureToMemoryKHR(VkCommandBuffer commandBuffer, |
| const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| auto accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src); |
| if (accel_state) { |
| auto buffer_state = Get<BUFFER_STATE>(accel_state->create_infoKHR.buffer); |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *buffer_state, error_obj.location.dot(Field::pInfo).dot(Field::src), |
| "VUID-vkCmdCopyAccelerationStructureToMemoryKHR-None-03559"); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCopyMemoryToAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, |
| const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| |
| auto accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst); |
| if (accel_state) { |
| skip |= ValidateHostVisibleMemoryIsBoundToBuffer(*accel_state->buffer_state, |
| error_obj.location.dot(Field::pInfo).dot(Field::dst), |
| "VUID-vkCopyMemoryToAccelerationStructureKHR-buffer-03730"); |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdCopyMemoryToAccelerationStructureKHR(VkCommandBuffer commandBuffer, |
| const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| auto accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst); |
| if (accel_state) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *accel_state->buffer_state, |
| error_obj.location.dot(Field::pInfo).dot(Field::dst), |
| "VUID-vkCmdCopyMemoryToAccelerationStructureKHR-buffer-03745"); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateCmdRayQueryState(const CMD_BUFFER_STATE &cb_state, const VkPipelineBindPoint bind_point, |
| const Location &loc) const { |
| bool skip = false; |
| const DrawDispatchVuid &vuid = GetDrawDispatchVuid(loc.function); |
| const auto lv_bind_point = ConvertToLvlBindPoint(bind_point); |
| const auto &last_bound = cb_state.lastBound[lv_bind_point]; |
| const auto *pipe = last_bound.pipeline_state; |
| |
| bool ray_query_shader = false; |
| if (nullptr != pipe) { |
| if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { |
| ray_query_shader = true; |
| } else { |
| // TODO - Loop through shader for RayQueryKHR for draw/dispatch commands |
| } |
| } |
| |
| if (cb_state.unprotected == false && ray_query_shader) { |
| skip |= LogError(vuid.ray_query_protected_cb_03635, cb_state.commandBuffer(), loc, |
| "can't use in protected command buffers for RayQuery operations."); |
| } |
| |
| return skip; |
| } |
| |
| uint32_t CoreChecks::CalcTotalShaderGroupCount(const PIPELINE_STATE &pipeline) const { |
| uint32_t total = 0; |
| if (pipeline.GetCreateInfoSType() == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR) { |
| const auto &create_info = pipeline.GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>(); |
| total = create_info.groupCount; |
| |
| if (create_info.pLibraryInfo) { |
| for (uint32_t i = 0; i < create_info.pLibraryInfo->libraryCount; ++i) { |
| auto library_pipeline_state = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[i]); |
| total += CalcTotalShaderGroupCount(*library_pipeline_state.get()); |
| } |
| } |
| } else if (pipeline.GetCreateInfoSType() == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV) { |
| const auto &create_info = pipeline.GetCreateInfo<VkRayTracingPipelineCreateInfoNV>(); |
| total = create_info.groupCount; |
| |
| if (create_info.pLibraryInfo) { |
| for (uint32_t i = 0; i < create_info.pLibraryInfo->libraryCount; ++i) { |
| auto library_pipeline_state = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[i]); |
| total += CalcTotalShaderGroupCount(*library_pipeline_state.get()); |
| } |
| } |
| } |
| |
| return total; |
| } |
| |
| bool CoreChecks::PreCallValidateGetRayTracingShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, |
| uint32_t groupCount, size_t dataSize, void *pData, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| auto pPipeline = Get<PIPELINE_STATE>(pipeline); |
| if (!pPipeline) { |
| return skip; |
| } |
| const PIPELINE_STATE &pipeline_state = *pPipeline; |
| if (pipeline_state.create_flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) { |
| if (!enabled_features.pipeline_library_group_handles_features.pipelineLibraryGroupHandles) { |
| skip |= LogError("VUID-vkGetRayTracingShaderGroupHandlesKHR-pipeline-07828", pipeline, |
| error_obj.location.dot(Field::pipeline), |
| "was created with %s, but the pipelineLibraryGroupHandles feature was not enabled.", |
| string_VkPipelineCreateFlags(pipeline_state.create_flags).c_str()); |
| } |
| } |
| if (dataSize < (phys_dev_ext_props.ray_tracing_props_khr.shaderGroupHandleSize * groupCount)) { |
| skip |= |
| LogError("VUID-vkGetRayTracingShaderGroupHandlesKHR-dataSize-02420", device, error_obj.location.dot(Field::dataSize), |
| "(%zu) must be at least " |
| "shaderGroupHandleSize (%" PRIu32 ") * groupCount (%" PRIu32 ").", |
| dataSize, phys_dev_ext_props.ray_tracing_props_khr.shaderGroupHandleSize, groupCount); |
| } |
| |
| const uint32_t total_group_count = CalcTotalShaderGroupCount(pipeline_state); |
| |
| if (firstGroup >= total_group_count) { |
| skip |= LogError("VUID-vkGetRayTracingShaderGroupHandlesKHR-firstGroup-04050", device, |
| error_obj.location.dot(Field::firstGroup), |
| "(%" PRIu32 ") must be less than the number of shader groups in pipeline (%" PRIu32 ").", firstGroup, |
| total_group_count); |
| } |
| if ((firstGroup + groupCount) > total_group_count) { |
| skip |= LogError("VUID-vkGetRayTracingShaderGroupHandlesKHR-firstGroup-02419", device, |
| error_obj.location.dot(Field::firstGroup), |
| "(%" PRIu32 ") plus groupCount (%" PRIu32 |
| ") must be less than or equal to the number " |
| "of shader groups in pipeline (%" PRIu32 ").", |
| firstGroup, groupCount, total_group_count); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, |
| uint32_t firstGroup, uint32_t groupCount, |
| size_t dataSize, void *pData, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| if (dataSize < (phys_dev_ext_props.ray_tracing_props_khr.shaderGroupHandleCaptureReplaySize * groupCount)) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-dataSize-03484", device, |
| error_obj.location.dot(Field::dataSize), |
| "(%zu) must be at least " |
| "shaderGroupHandleCaptureReplaySize (%" PRIu32 ") * groupCount (%" PRIu32 ").", |
| dataSize, phys_dev_ext_props.ray_tracing_props_khr.shaderGroupHandleCaptureReplaySize, groupCount); |
| } |
| auto pipeline_state = Get<PIPELINE_STATE>(pipeline); |
| if (!pipeline_state) { |
| return skip; |
| } |
| const auto &create_info = pipeline_state->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>(); |
| if (create_info.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) { |
| if (!enabled_features.pipeline_library_group_handles_features.pipelineLibraryGroupHandles) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-pipeline-07829", pipeline, |
| error_obj.location.dot(Field::pipeline), |
| "was created with %s, but the pipelineLibraryGroupHandles feature was not enabled.", |
| string_VkPipelineCreateFlags(create_info.flags).c_str()); |
| } |
| } |
| |
| const uint32_t total_group_count = CalcTotalShaderGroupCount(*pipeline_state); |
| |
| if (firstGroup >= total_group_count) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-firstGroup-04051", device, |
| error_obj.location.dot(Field::firstGroup), |
| "(%" PRIu32 |
| ") must be less than the number of shader " |
| "groups in pipeline (%" PRIu32 ").", |
| firstGroup, total_group_count); |
| } |
| if ((firstGroup + groupCount) > total_group_count) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-firstGroup-03483", device, |
| error_obj.location.dot(Field::firstGroup), |
| "(%" PRIu32 ") plus groupCount (%" PRIu32 |
| ") must be less than or equal to the number of shader groups in pipeline (%" PRIu32 ").", |
| firstGroup, groupCount, total_group_count); |
| } |
| if (!(create_info.flags & VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR)) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-pipeline-03607", pipeline, |
| error_obj.location.dot(Field::pipeline), "was created with %s.", |
| string_VkPipelineCreateFlags(create_info.flags).c_str()); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer); |
| return ValidateExtendedDynamicState(*cb_state, error_obj.location, VK_TRUE, nullptr, nullptr); |
| } |
| |
| bool CoreChecks::PreCallValidateGetRayTracingShaderGroupStackSizeKHR(VkDevice device, VkPipeline pipeline, uint32_t group, |
| VkShaderGroupShaderKHR groupShader, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| auto pipeline_state = Get<PIPELINE_STATE>(pipeline); |
| if (pipeline_state) { |
| if (pipeline_state->pipeline_type != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { |
| skip |= LogError("VUID-vkGetRayTracingShaderGroupStackSizeKHR-pipeline-04622", pipeline, |
| error_obj.location.dot(Field::pipeline), "must be a ray-tracing pipeline, but is a %s pipeline.", |
| string_VkPipelineBindPoint(pipeline_state->pipeline_type)); |
| } else if (group >= pipeline_state->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>().groupCount) { |
| skip |= |
| LogError("VUID-vkGetRayTracingShaderGroupStackSizeKHR-group-03608", pipeline, error_obj.location.dot(Field::group), |
| "(%" PRIu32 ") must be less than the number of shader groups in pipeline (%" PRIu32 ").", group, |
| pipeline_state->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>().groupCount); |
| } |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateGeometryTrianglesNV(const VkGeometryTrianglesNV &triangles, const Location &loc) const { |
| bool skip = false; |
| |
| auto vb_state = Get<BUFFER_STATE>(triangles.vertexData); |
| if (vb_state != nullptr && vb_state->createInfo.size <= triangles.vertexOffset) { |
| skip |= LogError("VUID-VkGeometryTrianglesNV-vertexOffset-02428", device, loc, "is invalid."); |
| } |
| |
| auto ib_state = Get<BUFFER_STATE>(triangles.indexData); |
| if (ib_state != nullptr && ib_state->createInfo.size <= triangles.indexOffset) { |
| skip |= LogError("VUID-VkGeometryTrianglesNV-indexOffset-02431", device, loc, "is invalid."); |
| } |
| |
| auto td_state = Get<BUFFER_STATE>(triangles.transformData); |
| if (td_state != nullptr && td_state->createInfo.size <= triangles.transformOffset) { |
| skip |= LogError("VUID-VkGeometryTrianglesNV-transformOffset-02437", device, loc, "is invalid."); |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateGeometryAABBNV(const VkGeometryAABBNV &aabbs, const Location &loc) const { |
| bool skip = false; |
| |
| auto aabb_state = Get<BUFFER_STATE>(aabbs.aabbData); |
| if (aabb_state != nullptr && aabb_state->createInfo.size > 0 && aabb_state->createInfo.size <= aabbs.offset) { |
| skip |= LogError("VUID-VkGeometryAABBNV-offset-02439", device, loc, "is invalid."); |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateGeometryNV(const VkGeometryNV &geometry, const Location &loc) const { |
| bool skip = false; |
| if (geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_NV) { |
| skip = ValidateGeometryTrianglesNV(geometry.geometry.triangles, loc); |
| } else if (geometry.geometryType == VK_GEOMETRY_TYPE_AABBS_NV) { |
| skip = ValidateGeometryAABBNV(geometry.geometry.aabbs, loc); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateRaytracingShaderBindingTable(VkCommandBuffer commandBuffer, const Location &table_loc, |
| const char *vuid_single_device_memory, const char *vuid_binding_table_flag, |
| const VkStridedDeviceAddressRegionKHR &binding_table) const { |
| bool skip = false; |
| |
| if (binding_table.deviceAddress == 0 || binding_table.size == 0) { |
| return skip; |
| } |
| |
| const auto buffer_states = GetBuffersByAddress(binding_table.deviceAddress); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-VkStridedDeviceAddressRegionKHR-size-04631", commandBuffer, table_loc.dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") has no buffer associated with it.", binding_table.deviceAddress); |
| } else { |
| const sparse_container::range<VkDeviceSize> requested_range(binding_table.deviceAddress, |
| binding_table.deviceAddress + binding_table.size - 1); |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<4> buffer_address_validator = {{{ |
| {vuid_single_device_memory, LogObjectList(commandBuffer), |
| [this, commandBuffer, table_loc, vuid_single_device_memory](const BUFFER_STATE_PTR &buffer_state, |
| std::string *out_error_msg) { |
| if (!out_error_msg) { |
| return !buffer_state->sparse && buffer_state->IsMemoryBound(); |
| } else { |
| return ValidateMemoryIsBoundToBuffer(commandBuffer, *buffer_state, table_loc.dot(Field::deviceAddress), |
| vuid_single_device_memory); |
| } |
| }}, |
| |
| {vuid_binding_table_flag, LogObjectList(commandBuffer), |
| [](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| if (!(static_cast<uint32_t>(buffer_state->usage) & VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR)) { |
| if (out_error_msg) { |
| *out_error_msg += "buffer has usage " + string_VkBufferUsageFlags2KHR(buffer_state->usage) + '\n'; |
| } |
| return false; |
| } |
| return true; |
| }, |
| []() { |
| return "The following buffers have not been created with the VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR " |
| "usage flag:\n"; |
| }}, |
| |
| {"VUID-VkStridedDeviceAddressRegionKHR-size-04631", LogObjectList(commandBuffer), |
| [&requested_range](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| const auto buffer_address_range = buffer_state->DeviceAddressRange(); |
| if (!buffer_address_range.includes(requested_range)) { |
| if (out_error_msg) { |
| const std::string buffer_address_range_string = string_range_hex(buffer_address_range); |
| *out_error_msg += "buffer device address range is " + buffer_address_range_string + '\n'; |
| } |
| return false; |
| } |
| |
| return true; |
| }, |
| [table_loc, requested_range_string = string_range_hex(requested_range)]() { |
| return "The following buffers do not include " + table_loc.Fields() + " buffer device address range " + |
| requested_range_string + ":\n"; |
| }}, |
| |
| {"VUID-VkStridedDeviceAddressRegionKHR-size-04632", LogObjectList(commandBuffer), |
| [&binding_table](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| if (binding_table.stride > buffer_state->createInfo.size) { |
| if (out_error_msg) { |
| *out_error_msg += "buffer size is " + std::to_string(buffer_state->createInfo.size) + '\n'; |
| } |
| return false; |
| } |
| return true; |
| }, |
| [table_loc, &binding_table]() { |
| return "The following buffers have a size inferior to " + table_loc.Fields() + "->stride (" + |
| std::to_string(binding_table.stride) + "):\n"; |
| ; |
| }}, |
| }}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer(*this, buffer_states, table_loc.StringFunc(), |
| table_loc.dot(Field::deviceAddress).Fields(), |
| binding_table.deviceAddress); |
| } |
| |
| return skip; |
| } |