| /* Copyright (c) 2015-2024 The Khronos Group Inc. |
| * Copyright (c) 2015-2024 Valve Corporation |
| * Copyright (c) 2015-2024 LunarG, Inc. |
| * Copyright (C) 2015-2024 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 vvl::DeviceMemory *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<vvl::Buffer>(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<vvl::AccelerationStructureNV>(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<vvl::DeviceMemory>(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<vvl::AccelerationStructureNV>(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::ValidateAccelerationStructuresMemoryAlisasing(VkCommandBuffer commandBuffer, uint32_t infoCount, |
| const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, |
| uint32_t info_i, const ErrorObject &error_obj) const { |
| using sparse_container::range; |
| |
| bool skip = false; |
| const VkAccelerationStructureBuildGeometryInfoKHR &info = pInfos[info_i]; |
| const Location info_i_loc = error_obj.location.dot(Field::pInfos, info_i); |
| const auto src_as_state = Get<vvl::AccelerationStructureKHR>(info.srcAccelerationStructure); |
| const auto dst_as_state = Get<vvl::AccelerationStructureKHR>(info.dstAccelerationStructure); |
| |
| auto validate_no_as_buffer_memory_overlap = |
| [this, commandBuffer, error_obj](const vvl::AccelerationStructureKHR &accel_struct_a, const Location &location_a, |
| const vvl::Buffer &buffer_a, const sparse_container::range<VkDeviceSize> &range_a, |
| |
| const vvl::AccelerationStructureKHR &accel_struct_b, const Location &location_b, |
| const vvl::Buffer &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()); |
| skip |= LogError( |
| vuid, objlist, error_obj.location, |
| "memory backing buffer (%s) used as storage for %s (%s) overlaps memory backing buffer (%s) used as " |
| "storage for %s (%s). Overlapped memory is (%s) on range %s.", |
| FormatHandle(buffer_a).c_str(), location_a.Fields().c_str(), FormatHandle(accel_struct_a.Handle()).c_str(), |
| FormatHandle(buffer_b).c_str(), location_b.Fields().c_str(), FormatHandle(accel_struct_b.Handle()).c_str(), |
| FormatHandle(memory).c_str(), string_range_hex(overlap_range).c_str()); |
| } |
| |
| return skip; |
| }; |
| |
| if (info.srcAccelerationStructure != info.dstAccelerationStructure && src_as_state && dst_as_state) { |
| const std::shared_ptr<vvl::Buffer> src_as_buffer = src_as_state->buffer_state; |
| const std::shared_ptr<vvl::Buffer> dst_as_buffer = dst_as_state->buffer_state; |
| |
| if (src_as_buffer && dst_as_buffer) { |
| const range<VkDeviceSize> src_as_range(src_as_state->create_infoKHR.offset, src_as_state->create_infoKHR.size); |
| const range<VkDeviceSize> dst_as_range(dst_as_state->create_infoKHR.offset, dst_as_state->create_infoKHR.size); |
| |
| skip |= validate_no_as_buffer_memory_overlap(*src_as_state, info_i_loc.dot(Field::srcAccelerationStructure), |
| *src_as_buffer, src_as_range, *dst_as_state, |
| info_i_loc.dot(Field::dstAccelerationStructure), *dst_as_buffer, |
| dst_as_range, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03668"); |
| } |
| } |
| |
| for (auto [other_info_j, other_info] : vvl::enumerate(pInfos + info_i, infoCount - info_i)) { |
| // 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. |
| |
| other_info_j += info_i; |
| const Location other_info_j_loc = error_obj.location.dot(Field::pInfos, other_info_j); |
| // 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 vvl::Buffer &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.VkHandle(), |
| other_scratch_var_name_ss.str().c_str(), other_scratch->VkHandle(), 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 (info->mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR && src_as_state && |
| src_as_state->buffer_state) { |
| const vvl::Buffer &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.VkHandle(), |
| other_scratch_var_name_ss.str().c_str(), other_scratch->VkHandle(), 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 info->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(info->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 = info->scratchData.deviceAddress, |
| assumed_scratch_size = rt::ComputeScratchSize(device, info-> 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 |
| // info->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->Handle()) |
| << ", backed by " << FormatHandle(memory) |
| << " - overlap on VkDeviceMemory space range " |
| << string_range_hex(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 info |
| if (other_info_j != info_i) { |
| const auto other_dst_as_state = Get<vvl::AccelerationStructureKHR>(pInfos[other_info_j].dstAccelerationStructure); |
| const auto other_src_as_state = Get<vvl::AccelerationStructureKHR>(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) { |
| const vvl::Buffer &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 vvl::Buffer &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, info_i_loc.dot(Field::dstAccelerationStructure), buffer_a, range_a, *other_src_as_state, |
| other_info_j_loc.dot(Field::srcAccelerationStructure), 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) { |
| const vvl::Buffer &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 vvl::Buffer &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, info_i_loc.dot(Field::dstAccelerationStructure), buffer_a, range_a, *other_dst_as_state, |
| other_info_j_loc.dot(Field::dstAccelerationStructure), buffer_b, range_b, |
| "VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702"); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateAccelerationBuffers(VkCommandBuffer cmd_buffer, uint32_t info_i, |
| const VkAccelerationStructureBuildGeometryInfoKHR &info, |
| const VkAccelerationStructureBuildRangeInfoKHR *geometry_build_ranges, |
| const Location &info_loc) const { |
| bool skip = false; |
| |
| 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; |
| }; |
| |
| const Location pp_build_range_info_loc(info_loc.function, Field::ppBuildRangeInfos, info_i); |
| for (uint32_t geom_i = 0; geom_i < info.geometryCount; ++geom_i) { |
| const Location p_geom_loc = info_loc.dot(info.pGeometries ? Field::pGeometries : Field::ppGeometries, geom_i); |
| const Location p_geom_geom_loc = p_geom_loc.dot(Field::geometry); |
| const Location p_geom_geom_triangles_loc = p_geom_geom_loc.dot(Field::triangles); |
| const VkAccelerationStructureGeometryKHR &geom_data = rt::GetGeometry(info, geom_i); |
| |
| switch (geom_data.geometryType) { |
| case VK_GEOMETRY_TYPE_TRIANGLES_KHR: // == VK_GEOMETRY_TYPE_TRIANGLES_NV |
| { |
| skip |= |
| buffer_check(geom_i, geom_data.geometry.triangles.vertexData, p_geom_geom_triangles_loc.dot(Field::vertexData)); |
| skip |= |
| buffer_check(geom_i, geom_data.geometry.triangles.indexData, p_geom_geom_triangles_loc.dot(Field::indexData)); |
| skip |= buffer_check(geom_i, geom_data.geometry.triangles.transformData, |
| p_geom_geom_triangles_loc.dot(Field::transformData)); |
| |
| auto vertex_buffer_states = GetBuffersByAddress(geom_data.geometry.triangles.vertexData.deviceAddress); |
| if (vertex_buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03804", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::vertexData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not an address belonging to an existing buffer.", |
| geom_data.geometry.triangles.vertexData.deviceAddress); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03805", LogObjectList(cmd_buffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, vertex_buffer_states, p_geom_geom_triangles_loc.dot(Field::vertexData).dot(Field::deviceAddress), |
| geom_data.geometry.triangles.vertexData.deviceAddress); |
| } |
| |
| if (geom_data.geometry.triangles.indexType != VK_INDEX_TYPE_NONE_KHR) { |
| auto index_buffer_states = GetBuffersByAddress(geom_data.geometry.triangles.indexData.deviceAddress); |
| if (index_buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03806", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::indexData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not an address belonging to an existing buffer. %s is %s.", |
| geom_data.geometry.triangles.indexData.deviceAddress, |
| p_geom_geom_triangles_loc.dot(Field::indexType).Fields().c_str(), |
| string_VkIndexType(geom_data.geometry.triangles.indexType)); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03807", LogObjectList(cmd_buffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| if (!buffer_state->sparse && !buffer_state->IsMemoryBound()) { |
| if (out_error_msg) { |
| if (const auto mem_state = buffer_state->MemState(); |
| mem_state && mem_state->Destroyed()) { |
| *out_error_msg += "buffer is bound to memory (" + FormatHandle(mem_state->Handle()) + |
| ") but it has been freed"; |
| } else { |
| *out_error_msg += "buffer has not been bound to memory"; |
| } |
| } |
| return false; |
| } |
| return true; |
| }, |
| []() { return "The following buffers are not bound to memory or it has been freed:\n"; }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, index_buffer_states, p_geom_geom_triangles_loc.dot(Field::indexData).dot(Field::deviceAddress), |
| geom_data.geometry.triangles.indexData.deviceAddress); |
| } |
| |
| if (const auto src_as_state = Get<vvl::AccelerationStructureKHR>(info.srcAccelerationStructure)) { |
| if (geom_i < src_as_state->build_range_infos.size()) { |
| if (const uint32_t recorded_first_vertex = src_as_state->build_range_infos[geom_i].firstVertex; |
| recorded_first_vertex != geometry_build_ranges[geom_i].firstVertex) { |
| const LogObjectList objlist(cmd_buffer, info.srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-firstVertex-03770", objlist, p_geom_loc, |
| " has corresponding VkAccelerationStructureBuildRangeInfoKHR %s[%" PRIu32 |
| "], but this build range has its firstVertex member set to (%" PRIu32 |
| ") when it was last specified as (%" PRIu32 ").", |
| pp_build_range_info_loc.Fields().c_str(), geom_i, |
| geometry_build_ranges[geom_i].firstVertex, recorded_first_vertex); |
| } |
| |
| if (const uint32_t recorded_primitive_count = src_as_state->build_range_infos[geom_i].primitiveCount; |
| recorded_primitive_count != geometry_build_ranges[geom_i].primitiveCount) { |
| const LogObjectList objlist(cmd_buffer, info.srcAccelerationStructure); |
| skip |= |
| LogError("VUID-vkCmdBuildAccelerationStructuresKHR-primitiveCount-03769", objlist, p_geom_loc, |
| " has corresponding VkAccelerationStructureBuildRangeInfoKHR %s[%" PRIu32 |
| "], but this build range has its primitiveCount member set to (%" PRIu32 |
| ") when it was last specified as (%" PRIu32 ").", |
| pp_build_range_info_loc.Fields().c_str(), geom_i, |
| geometry_build_ranges[geom_i].primitiveCount, recorded_primitive_count); |
| } |
| } |
| } |
| } |
| |
| VkFormatProperties vertex_format_props{}; |
| DispatchGetPhysicalDeviceFormatProperties(physical_device, geom_data.geometry.triangles.vertexFormat, |
| &vertex_format_props); |
| if (!(vertex_format_props.bufferFeatures & VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)) { |
| skip |= LogError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::vertexFormat), |
| "is %s, and only has the following VkFormatProperties::bufferFeatures: %s.", |
| string_VkFormat(geom_data.geometry.triangles.vertexFormat), |
| string_VkFormatFeatureFlags(vertex_format_props.bufferFeatures).c_str()); |
| } |
| // Only try to get format info if vertex format is valid |
| else { |
| const VKU_FORMAT_INFO format_info = vkuGetFormatInfo(geom_data.geometry.triangles.vertexFormat); |
| uint32_t min_component_bits_size = format_info.components[0].size; |
| for (uint32_t component_i = 1; component_i < format_info.component_count; ++component_i) { |
| min_component_bits_size = std::min(format_info.components[component_i].size, min_component_bits_size); |
| } |
| const uint32_t min_component_byte_size = min_component_bits_size / 8; |
| if (SafeModulo(geom_data.geometry.triangles.vertexData.deviceAddress, min_component_byte_size) != 0) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03711", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::vertexData).dot(Field::deviceAddress), |
| "is 0x%" PRIx64 " and is not aligned to the minimum component byte size (%" PRIu32 |
| ") of its corresponding vertex " |
| "format (%s).", |
| geom_data.geometry.triangles.vertexData.deviceAddress, min_component_byte_size, |
| string_VkFormat(geom_data.geometry.triangles.vertexFormat)); |
| } |
| if (SafeModulo(geom_data.geometry.triangles.vertexStride, min_component_byte_size) != 0) { |
| skip |= LogError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03735", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::vertexStride), |
| "is %" PRIu64 " and is not aligned to the minimum component byte size (%" PRIu32 |
| ") of its corresponding vertex " |
| "format (%s).", |
| geom_data.geometry.triangles.vertexStride, min_component_byte_size, |
| string_VkFormat(geom_data.geometry.triangles.vertexFormat)); |
| } |
| } |
| if (geom_data.geometry.triangles.transformData.deviceAddress != 0) { |
| auto tranform_buffer_states = GetBuffersByAddress(geom_data.geometry.triangles.transformData.deviceAddress); |
| if (tranform_buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03808", cmd_buffer, |
| p_geom_geom_triangles_loc.dot(Field::transformData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not an address belonging to an existing buffer.", |
| geom_data.geometry.triangles.transformData.deviceAddress); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03809", LogObjectList(cmd_buffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, |
| out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, tranform_buffer_states, |
| p_geom_geom_triangles_loc.dot(Field::transformData).dot(Field::deviceAddress), |
| geom_data.geometry.triangles.transformData.deviceAddress); |
| } |
| } |
| break; |
| } |
| case VK_GEOMETRY_TYPE_INSTANCES_KHR: { |
| const Location instances_loc = p_geom_geom_loc.dot(Field::instances); |
| const Location instances_data_loc = instances_loc.dot(Field::data); |
| |
| skip |= buffer_check(geom_i, geom_data.geometry.instances.data, instances_data_loc); |
| |
| auto buffer_states = GetBuffersByAddress(geom_data.geometry.instances.data.deviceAddress); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03813", cmd_buffer, |
| instances_data_loc.dot(Field::deviceAddress), |
| "(%" PRIu64 ") is not an address belonging to an existing buffer.", |
| geom_data.geometry.instances.data.deviceAddress); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03814", LogObjectList(cmd_buffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer(*this, buffer_states, |
| instances_data_loc.dot(Field::deviceAddress), |
| geom_data.geometry.instances.data.deviceAddress); |
| } |
| |
| break; |
| } |
| case VK_GEOMETRY_TYPE_AABBS_KHR: // == VK_GEOMETRY_TYPE_AABBS_NV |
| { |
| skip |= buffer_check(geom_i, geom_data.geometry.aabbs.data, p_geom_geom_loc.dot(Field::aabbs).dot(Field::data)); |
| |
| auto aabb_buffer_states = GetBuffersByAddress(geom_data.geometry.aabbs.data.deviceAddress); |
| if (aabb_buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03811", cmd_buffer, |
| p_geom_geom_loc.dot(Field::aabbs).dot(Field::data).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not an address belonging to an existing buffer.", |
| geom_data.geometry.aabbs.data.deviceAddress); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03812", LogObjectList(cmd_buffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, aabb_buffer_states, p_geom_geom_loc.dot(Field::aabbs).dot(Field::data).dot(Field::deviceAddress), |
| geom_data.geometry.aabbs.data.deviceAddress); |
| } |
| break; |
| } |
| default: |
| // no-op |
| break; |
| } |
| } |
| |
| if (const auto dst_as_state = Get<vvl::AccelerationStructureKHR>(info.dstAccelerationStructure)) { |
| const VkDeviceSize as_minimum_size = rt::ComputeAccelerationStructureSize(device, info, geometry_build_ranges); |
| if (dst_as_state->create_infoKHR.size < as_minimum_size) { |
| const LogObjectList objlist(cmd_buffer, info.dstAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03675", objlist, |
| info_loc.dot(Field::dstAccelerationStructure), |
| " was created with size (%" PRIu64 |
| "), but an acceleration structure build with corresponding ppBuildRangeInfos[%" PRIu32 |
| "] requires a minimum size of (%" PRIu64 ").", |
| dst_as_state->create_infoKHR.size, info_i, as_minimum_size); |
| } |
| } |
| |
| const auto buffer_states = GetBuffersByAddress(info.scratchData.deviceAddress); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03802", device, |
| info_loc.dot(Field::scratchData).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") has no buffer is associated with it.", info.scratchData.deviceAddress); |
| } else { |
| const VkDeviceSize scratch_size = rt::ComputeScratchSize(device, info, geometry_build_ranges); |
| const sparse_container::range<VkDeviceSize> scratch_address_range(info.scratchData.deviceAddress, |
| info.scratchData.deviceAddress + scratch_size); |
| const char *scratch_address_range_vuid = info.mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR |
| ? "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03671" |
| : "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03672"; |
| |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<5> buffer_address_validator = {{{ |
| {"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03803", LogObjectList(cmd_buffer), |
| [this, info_loc, cmd_buffer](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(cmd_buffer, *buffer_state, |
| info_loc.dot(Field::scratchData).dot(Field::deviceAddress), |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03803"); |
| } |
| }}, |
| |
| {"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674", LogObjectList(cmd_buffer), |
| [](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| if (!(buffer_state->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) { |
| if (out_error_msg) { |
| *out_error_msg += "buffer usage is " + string_VkBufferUsageFlags2KHR(buffer_state->usage) + '\n'; |
| } |
| return false; |
| } |
| return true; |
| }, |
| []() { return "The following buffers are missing VK_BUFFER_USAGE_STORAGE_BUFFER_BIT usage flag:"; }}, |
| |
| {scratch_address_range_vuid, LogObjectList(cmd_buffer), |
| [scratch_address_range](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| const sparse_container::range<VkDeviceSize> buffer_address_range = buffer_state->DeviceAddressRange(); |
| |
| if (!buffer_address_range.includes(scratch_address_range)) { |
| if (out_error_msg) { |
| *out_error_msg += "buffer address range is " + string_range_hex(buffer_address_range) + '\n'; |
| } |
| return false; |
| } |
| return true; |
| }, |
| [scratch_address_range]() { |
| return "The following buffers have an address range that does not include scratch address range " + |
| string_range_hex(scratch_address_range) + ":"; |
| }}, |
| |
| }}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, buffer_states, info_loc.dot(Field::scratchData).dot(Field::deviceAddress), info.scratchData.deviceAddress); |
| } |
| |
| 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<vvl::CommandBuffer>(commandBuffer); |
| assert(cb_state); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| if (!pInfos || !ppBuildRangeInfos) { |
| return skip; |
| } |
| |
| for (const auto [info_i, info] : vvl::enumerate(pInfos, infoCount)) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, info_i); |
| |
| const auto src_as_state = Get<vvl::AccelerationStructureKHR>(info->srcAccelerationStructure); |
| const auto dst_as_state = Get<vvl::AccelerationStructureKHR>(info->dstAccelerationStructure); |
| |
| if (dst_as_state != nullptr) { |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *dst_as_state->buffer_state, |
| info_loc.dot(Field::dstAccelerationStructure), |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03707"); |
| } |
| |
| if (info->mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) { |
| if (src_as_state->built && |
| !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| 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, info->srcAccelerationStructure); |
| 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 (info->flags != src_as_state->build_info_khr.flags) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= |
| LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03759", objlist, info_loc.dot(Field::mode), |
| "is VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, but %s (%s) must have the same value which" |
| " was specified when srcAccelerationStructure was last built (%s).", |
| info_loc.dot(Field::flags).Fields().c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(info->flags).c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(src_as_state->build_info_khr.flags).c_str()); |
| } |
| if (info->type != src_as_state->build_info_khr.type) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| 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(info->type), |
| string_VkAccelerationStructureTypeKHR(src_as_state->build_info_khr.type)); |
| } |
| if (info->geometryCount != src_as_state->build_info_khr.geometryCount) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| 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 ").", |
| info->geometryCount, src_as_state->build_info_khr.geometryCount); |
| } else if (info->pGeometries || info->ppGeometries) { |
| for (uint32_t geom_i = 0; geom_i < info->geometryCount; ++geom_i) { |
| const VkAccelerationStructureGeometryKHR &updated_geometry = |
| info->pGeometries ? info->pGeometries[geom_i] : *info->ppGeometries[geom_i]; |
| |
| const safe_VkAccelerationStructureGeometryKHR &last_geometry = |
| src_as_state->build_info_khr.pGeometries ? src_as_state->build_info_khr.pGeometries[geom_i] |
| : *src_as_state->build_info_khr.ppGeometries[geom_i]; |
| |
| const Location geom_loc = |
| info_loc.dot(info->pGeometries ? Field::pGeometries : Field::ppGeometries, geom_i); |
| |
| if (updated_geometry.geometryType != last_geometry.geometryType) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03761", objlist, |
| geom_loc.dot(Field::geometryType), "is %s but was last specified as %s.", |
| string_VkGeometryTypeKHR(updated_geometry.geometryType), |
| string_VkGeometryTypeKHR(last_geometry.geometryType)); |
| } |
| |
| if (updated_geometry.flags != last_geometry.flags) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03762", objlist, |
| geom_loc.dot(Field::flags), "is %s but was last specified as %s.", |
| string_VkGeometryFlagsKHR(updated_geometry.flags).c_str(), |
| string_VkGeometryFlagsKHR(last_geometry.geometryType).c_str()); |
| } |
| |
| if (updated_geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { |
| if (updated_geometry.geometry.triangles.vertexFormat != last_geometry.geometry.triangles.vertexFormat) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03763", objlist, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::vertexFormat), |
| "is %s but was last specified as %s.", |
| string_VkFormat(updated_geometry.geometry.triangles.vertexFormat), |
| string_VkFormat(last_geometry.geometry.triangles.vertexFormat)); |
| } |
| } |
| |
| if (updated_geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { |
| if (updated_geometry.geometry.triangles.maxVertex != last_geometry.geometry.triangles.maxVertex) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03764", objlist, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::maxVertex), |
| "is %" PRIu32 " but was last specified as %" PRIu32 ".", |
| updated_geometry.geometry.triangles.maxVertex, |
| last_geometry.geometry.triangles.maxVertex); |
| } |
| } |
| |
| if (updated_geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { |
| if (updated_geometry.geometry.triangles.indexType != last_geometry.geometry.triangles.indexType) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03765", objlist, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::indexType), |
| "is %s but was last specified as %s.", |
| string_VkIndexType(updated_geometry.geometry.triangles.indexType), |
| string_VkIndexType(last_geometry.geometry.triangles.indexType)); |
| } |
| } |
| |
| if (updated_geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { |
| if (last_geometry.geometry.triangles.transformData.deviceAddress == 0 && |
| updated_geometry.geometry.triangles.transformData.deviceAddress != 0) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03766", objlist, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::transformData), |
| "is 0x%" PRIx64 " but was last specified as NULL.", |
| updated_geometry.geometry.triangles.transformData.deviceAddress); |
| } |
| } |
| |
| if (updated_geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR) { |
| if (last_geometry.geometry.triangles.transformData.deviceAddress != 0 && |
| updated_geometry.geometry.triangles.transformData.deviceAddress == 0) { |
| const LogObjectList objlist(device, commandBuffer, info->srcAccelerationStructure); |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03767", objlist, |
| geom_loc.dot(Field::geometry).dot(Field::triangles).dot(Field::transformData), |
| "is NULL but was last specified as 0x%" PRIx64 ".", |
| last_geometry.geometry.triangles.transformData.deviceAddress); |
| } |
| } |
| } |
| } |
| } |
| } |
| if (info->type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) { |
| if (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 (info->type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) { |
| if (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(commandBuffer, info_i, *info, ppBuildRangeInfos[info_i], info_loc); |
| |
| skip |= ValidateAccelerationStructuresMemoryAlisasing(commandBuffer, infoCount, pInfos, info_i, error_obj); |
| } |
| |
| 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; |
| skip |= ValidateDeferredOperation(device, deferredOperation, error_obj.location.dot(Field::deferredOperation), |
| "VUID-vkBuildAccelerationStructuresKHR-deferredOperation-03678"); |
| |
| for (uint32_t i = 0; i < infoCount; ++i) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, i); |
| auto src_as_state = Get<vvl::AccelerationStructureKHR>(pInfos[i].srcAccelerationStructure); |
| auto dst_as_state = Get<vvl::AccelerationStructureKHR>(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 %s (%s) is different then srcAccelerationStructure value (%s).", |
| info_loc.dot(Field::flags).Fields().c_str(), |
| 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<vvl::CommandBuffer>(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<vvl::AccelerationStructureNV>(dst); |
| auto src_as_state = Get<vvl::AccelerationStructureNV>(src); |
| auto scratch_buffer_state = Get<vvl::Buffer>(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" |
| "[%s] must be identical to build info VkAccelerationStructureInfoNV::flags [%s].", |
| string_VkBuildAccelerationStructureFlagsKHR(dst_as_state->create_infoNV.info.flags).c_str(), |
| string_VkBuildAccelerationStructureFlagsKHR(pInfo->flags).c_str()); |
| } |
| 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("WARNING-vkCmdBuildAccelerationStructureNV-update-requirements", dst, error_obj.location, |
| "Updating %s but vkGetAccelerationStructureMemoryRequirementsNV() " |
| "has not been called for update scratch memory.", |
| FormatHandle(dst_as_state->Handle()).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("WARNING-vkCmdBuildAccelerationStructureNV-scratch-requirements", dst, error_obj.location, |
| "Assigning scratch buffer to %s but " |
| "vkGetAccelerationStructureMemoryRequirementsNV() has not been called for scratch memory.", |
| FormatHandle(dst_as_state->Handle()).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<vvl::Buffer>(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<vvl::CommandBuffer>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto dst_as_state = Get<vvl::AccelerationStructureNV>(dst); |
| auto src_as_state = Get<vvl::AccelerationStructureNV>(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<vvl::AccelerationStructureNV>(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<vvl::AccelerationStructureKHR>(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, const RecordObject &record_obj) { |
| 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<vvl::CommandBuffer>(commandBuffer); |
| cb_state->queryUpdates.emplace_back([accelerationStructureCount, firstQuery, queryPool]( |
| vvl::CommandBuffer &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<vvl::AccelerationStructureKHR>(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<vvl::CommandBuffer>(commandBuffer); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto query_pool_state = Get<vvl::QueryPool>(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<vvl::AccelerationStructureKHR>(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<vvl::CommandBuffer>(commandBuffer); |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| auto query_pool_state = Get<vvl::QueryPool>(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<vvl::AccelerationStructureNV>(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<vvl::CommandBuffer>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| if (!cb_state->unprotected) { |
| skip |= LogError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-commandBuffer-09547", commandBuffer, error_obj.location, |
| "called in a protected command buffer."); |
| } |
| for (uint32_t i = 0; i < infoCount; ++i) { |
| const Location info_loc = error_obj.location.dot(Field::pInfos, i); |
| auto src_as_state = Get<vvl::AccelerationStructureKHR>(pInfos[i].srcAccelerationStructure); |
| auto dst_as_state = Get<vvl::AccelerationStructureKHR>(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 %s (%s) is different than srcAccelerationStructure value (%s).", |
| info_loc.dot(Field::flags).Fields().c_str(), |
| 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<vvl::AccelerationStructureKHR>(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<vvl::AccelerationStructureKHR>(pInfo->src); |
| if (src_accel_state) { |
| auto buffer_state = Get<vvl::Buffer>(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<vvl::AccelerationStructureKHR>(pInfo->dst); |
| if (dst_accel_state) { |
| auto buffer_state = Get<vvl::Buffer>(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<vvl::CommandBuffer>(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<vvl::AccelerationStructureKHR>(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<vvl::AccelerationStructureKHR>(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::PreCallValidateDestroyDeferredOperationKHR(VkDevice device, VkDeferredOperationKHR operation, |
| const VkAllocationCallbacks *pAllocator, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| skip |= ValidateDeferredOperation(device, operation, error_obj.location.dot(Field::operation), |
| "VUID-vkDestroyDeferredOperationKHR-operation-03436"); |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, |
| const VkCopyAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| skip |= ValidateDeferredOperation(device, deferredOperation, error_obj.location.dot(Field::deferredOperation), |
| "VUID-vkCopyAccelerationStructureKHR-deferredOperation-03678"); |
| |
| 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<vvl::AccelerationStructureKHR>(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<vvl::AccelerationStructureKHR>(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::PreCallValidateCopyAccelerationStructureToMemoryKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, |
| const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| skip |= ValidateDeferredOperation(device, deferredOperation, error_obj.location.dot(Field::deferredOperation), |
| "VUID-vkCopyAccelerationStructureToMemoryKHR-deferredOperation-03678"); |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureToMemoryKHR(VkCommandBuffer commandBuffer, |
| const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| auto cb_state = GetRead<vvl::CommandBuffer>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| auto accel_state = Get<vvl::AccelerationStructureKHR>(pInfo->src); |
| if (accel_state) { |
| auto buffer_state = Get<vvl::Buffer>(accel_state->create_infoKHR.buffer); |
| skip |= ValidateMemoryIsBoundToBuffer(commandBuffer, *buffer_state, error_obj.location.dot(Field::pInfo).dot(Field::src), |
| "VUID-vkCmdCopyAccelerationStructureToMemoryKHR-None-03559"); |
| } |
| |
| const VkDeviceAddress dst_address = pInfo->dst.deviceAddress; |
| |
| const auto buffer_states = GetBuffersByAddress(dst_address); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdCopyAccelerationStructureToMemoryKHR-pInfo-03739", device, |
| error_obj.location.dot(Field::pInfo).dot(Field::dst).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not a valid buffer address.", dst_address); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdCopyAccelerationStructureToMemoryKHR-pInfo-03741", LogObjectList(commandBuffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, buffer_states, error_obj.location.dot(Field::pInfo).dot(Field::dst).dot(Field::deviceAddress), dst_address); |
| } |
| return skip; |
| } |
| |
| bool CoreChecks::PreCallValidateCopyMemoryToAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, |
| const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| skip |= ValidateDeferredOperation(device, deferredOperation, error_obj.location.dot(Field::deferredOperation), |
| "VUID-vkCopyMemoryToAccelerationStructureKHR-deferredOperation-03678"); |
| |
| auto accel_state = Get<vvl::AccelerationStructureKHR>(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<vvl::CommandBuffer>(commandBuffer); |
| assert(cb_state); |
| bool skip = false; |
| skip |= ValidateCmd(*cb_state, error_obj.location); |
| |
| auto accel_state = Get<vvl::AccelerationStructureKHR>(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"); |
| } |
| |
| const VkDeviceAddress src_address = pInfo->src.deviceAddress; |
| |
| const auto buffer_states = GetBuffersByAddress(src_address); |
| if (buffer_states.empty()) { |
| skip |= LogError("VUID-vkCmdCopyMemoryToAccelerationStructureKHR-pInfo-03742", device, |
| error_obj.location.dot(Field::pInfo).dot(Field::src).dot(Field::deviceAddress), |
| "(0x%" PRIx64 ") is not a valid buffer address.", src_address); |
| } else { |
| using BUFFER_STATE_PTR = ValidationStateTracker::BUFFER_STATE_PTR; |
| BufferAddressValidation<1> buffer_address_validator = { |
| {{{"VUID-vkCmdCopyMemoryToAccelerationStructureKHR-pInfo-03744", LogObjectList(commandBuffer), |
| [this](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}}}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer( |
| *this, buffer_states, error_obj.location.dot(Field::pInfo).dot(Field::src).dot(Field::deviceAddress), src_address); |
| } |
| |
| return skip; |
| } |
| |
| uint32_t CoreChecks::CalcTotalShaderGroupCount(const vvl::Pipeline &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<vvl::Pipeline>(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<vvl::Pipeline>(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<vvl::Pipeline>(pipeline); |
| if (!pPipeline) { |
| return skip; |
| } else if (pPipeline->pipeline_type != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { |
| skip |= |
| LogError("VUID-vkGetRayTracingShaderGroupHandlesKHR-pipeline-04619", pipeline, error_obj.location.dot(Field::pipeline), |
| "is a %s pipeline.", string_VkPipelineBindPoint(pPipeline->pipeline_type)); |
| return skip; |
| } |
| |
| const vvl::Pipeline &pipeline_state = *pPipeline; |
| if (pipeline_state.create_flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) { |
| if (!enabled_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_VkPipelineCreateFlags2KHR(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<vvl::Pipeline>(pipeline); |
| if (!pipeline_state) { |
| return skip; |
| } else if (pipeline_state->pipeline_type != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { |
| skip |= LogError("VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-pipeline-04620", pipeline, |
| error_obj.location.dot(Field::pipeline), "is a %s pipeline.", |
| string_VkPipelineBindPoint(pipeline_state->pipeline_type)); |
| return skip; |
| } |
| |
| const auto &create_info = pipeline_state->GetCreateInfo<VkRayTracingPipelineCreateInfoKHR>(); |
| if (create_info.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) { |
| if (!enabled_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<vvl::CommandBuffer>(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<vvl::Pipeline>(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), "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<vvl::Buffer>(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<vvl::Buffer>(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<vvl::Buffer>(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<vvl::Buffer>(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](const BUFFER_STATE_PTR &buffer_state, std::string *out_error_msg) { |
| return BufferAddressValidation<1>::ValidateMemoryBoundToBuffer(*this, buffer_state, out_error_msg); |
| }, |
| []() { return BufferAddressValidation<1>::ValidateMemoryBoundToBufferErrorMsgHeader(); }}, |
| |
| {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); |
| } |
| return false; |
| } |
| return true; |
| }, |
| []() { |
| return "The following buffers have not been created with the VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR " |
| "usage flag:"; |
| }}, |
| |
| {"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; |
| } |
| 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 + ':'; |
| }}, |
| |
| {"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); |
| } |
| 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) + "):"; |
| ; |
| }}, |
| }}}; |
| |
| skip |= buffer_address_validator.LogErrorsIfNoValidBuffer(*this, buffer_states, table_loc.dot(Field::deviceAddress), |
| binding_table.deviceAddress); |
| } |
| |
| return skip; |
| } |
| |
| bool CoreChecks::ValidateDeferredOperation(VkDevice device, VkDeferredOperationKHR deferred_operation, const Location &loc, |
| const char *vuid) const { |
| // validate in core check because need to make sure it is a valid VkDeferredOperationKHR object |
| bool skip = false; |
| if (deferred_operation != VK_NULL_HANDLE) { |
| VkResult result = DispatchGetDeferredOperationResultKHR(device, deferred_operation); |
| if (result == VK_NOT_READY) { |
| skip |= LogError(vuid, deferred_operation, loc.dot(Field::deferredOperation), "%s is not completed.", |
| FormatHandle(deferred_operation).c_str()); |
| } |
| } |
| return skip; |
| } |