layers: Add accel structure tracking and validation

Adds tracking and validation for ray tracing acceleration structures in
manner similar to buffers and images (adds memory links on bind commands,
adds usage links in build and copy commands).

More extension information:
- https://www.khronos.org/registry/vulkan/specs/1.1-extensions/
  html/vkspec.html#VK_NV_ray_tracing

Change-Id: I6c86f753e01e90de93aef7046fb83b44c03a8bca
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 501c997..676532e 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -167,6 +167,8 @@
             return GetImageState(VkImage(typed_handle.handle));
         case kVulkanObjectTypeBuffer:
             return GetBufferState(VkBuffer(typed_handle.handle));
+        case kVulkanObjectTypeAccelerationStructureNV:
+            return GetAccelerationStructureState(VkAccelerationStructureNV(typed_handle.handle));
         default:
             break;
     }
@@ -360,6 +362,27 @@
     }
 }
 
+// Create binding link between given acceleration structure and command buffer node
+void CoreChecks::AddCommandBufferBindingAccelerationStructure(CMD_BUFFER_STATE *cb_node, ACCELERATION_STRUCTURE_STATE *as_state) {
+    auto as_inserted = cb_node->object_bindings.emplace(as_state->acceleration_structure, kVulkanObjectTypeAccelerationStructureNV);
+    if (as_inserted.second) {
+        // Only need to complete the cross-reference if this is a new item
+        as_state->cb_bindings.insert(cb_node);
+        // Now update CB binding in MemObj mini CB list
+        for (auto mem_binding : as_state->GetBoundMemory()) {
+            DEVICE_MEMORY_STATE *pMemInfo = GetDevMemState(mem_binding);
+            if (pMemInfo) {
+                // Now update CBInfo's Mem reference list
+                auto mem_inserted = cb_node->memObjs.insert(mem_binding);
+                if (mem_inserted.second) {
+                    // Only need to complete the cross-reference if this is a new item
+                    pMemInfo->cb_bindings.insert(cb_node);
+                }
+            }
+        }
+    }
+}
+
 // For every mem obj bound to particular CB, free bindings related to that CB
 void CoreChecks::ClearCmdBufAndMemReferences(CMD_BUFFER_STATE *cb_node) {
     if (cb_node) {
@@ -449,6 +472,14 @@
     return result;
 }
 
+// Check to see if memory was bound to this acceleration structure
+bool CoreChecks::ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE *as_state, const char *api_name,
+                                                              const char *error_code) const {
+    return VerifyBoundMemoryIsValid(as_state->binding.mem,
+                                    VulkanTypedHandle(as_state->acceleration_structure, kVulkanObjectTypeAccelerationStructureNV),
+                                    api_name, error_code);
+}
+
 // SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
 // Corresponding valid usage checks are in ValidateSetMemBinding().
 void CoreChecks::SetMemBinding(VkDeviceMemory mem, BINDABLE *mem_binding, VkDeviceSize memory_offset,
@@ -1938,6 +1969,10 @@
             base_ptr = GetDevMemState(object_struct.Cast<VkDeviceMemory>());
             break;
         }
+        case kVulkanObjectTypeAccelerationStructureNV: {
+            base_ptr = GetAccelerationStructureState(object_struct.Cast<VkAccelerationStructureNV>());
+            break;
+        }
         default:
             // TODO : Any other objects to be handled here?
             assert(0);
@@ -2422,6 +2457,7 @@
     GetPhysicalDeviceExtProperties(gpu, dev_ext.vk_ext_vertex_attribute_divisor, &phys_dev_props->vtx_attrib_divisor_props);
     GetPhysicalDeviceExtProperties(gpu, dev_ext.vk_khr_depth_stencil_resolve, &phys_dev_props->depth_stencil_resolve_props);
     GetPhysicalDeviceExtProperties(gpu, dev_ext.vk_ext_transform_feedback, &phys_dev_props->transform_feedback_props);
+    GetPhysicalDeviceExtProperties(gpu, dev_ext.vk_nv_ray_tracing, &phys_dev_props->ray_tracing_props);
     if (state_tracker->device_extensions.vk_nv_cooperative_matrix) {
         // Get the needed cooperative_matrix properties
         auto cooperative_matrix_props = lvl_init_struct<VkPhysicalDeviceCooperativeMatrixPropertiesNV>();
@@ -3678,8 +3714,12 @@
             case kVulkanObjectTypeBuffer:
                 bindable_state = GetBufferState(obj.Cast<VkBuffer>());
                 break;
+            case kVulkanObjectTypeAccelerationStructureNV:
+                bindable_state = GetAccelerationStructureState(obj.Cast<VkAccelerationStructureNV>());
+                break;
+
             default:
-                // Should only have buffer or image objects bound to memory
+                // Should only have acceleration structure, buffer, or image objects bound to memory
                 assert(0);
         }
 
@@ -4055,12 +4095,12 @@
 }
 
 bool CoreChecks::ValidateInsertMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize memoryOffset,
-                                           VkMemoryRequirements memRequirements, bool is_image, bool is_linear,
+                                           VkMemoryRequirements memRequirements, VulkanObjectType object_type, bool is_linear,
                                            const char *api_name) {
     bool skip = false;
 
     MEMORY_RANGE range;
-    range.image = is_image;
+    range.image = object_type == kVulkanObjectTypeImage;
     range.handle = handle;
     range.linear = is_linear;
     range.memory = mem_info->mem;
@@ -4080,8 +4120,18 @@
     }
 
     if (memoryOffset >= mem_info->alloc_info.allocationSize) {
-        const char *error_code =
-            is_image ? "VUID-vkBindImageMemory-memoryOffset-01046" : "VUID-vkBindBufferMemory-memoryOffset-01031";
+        const char *error_code = nullptr;
+        if (object_type == kVulkanObjectTypeBuffer) {
+            error_code = "VUID-vkBindBufferMemory-memoryOffset-01031";
+        } else if (object_type == kVulkanObjectTypeImage) {
+            error_code = "VUID-vkBindImageMemory-memoryOffset-01046";
+        } else if (object_type == kVulkanObjectTypeAccelerationStructureNV) {
+            error_code = "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02451";
+        } else {
+            // Unsupported object type
+            assert(false);
+        }
+
         skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                        HandleToUint64(mem_info->mem), error_code,
                        "In %s, attempting to bind %s to %s, memoryOffset=0x%" PRIxLEAST64
@@ -4102,10 +4152,10 @@
 // is_image indicates an image object, otherwise handle is for a buffer
 // is_linear indicates a buffer or linear image
 void CoreChecks::InsertMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize memoryOffset,
-                                   VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
+                                   VkMemoryRequirements memRequirements, VulkanObjectType object_type, bool is_linear) {
     MEMORY_RANGE range;
 
-    range.image = is_image;
+    range.image = object_type == kVulkanObjectTypeImage;
     range.handle = handle;
     range.linear = is_linear;
     range.memory = mem_info->mem;
@@ -4129,54 +4179,83 @@
     for (auto tmp_range : tmp_alias_ranges) {
         tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
     }
-    if (is_image)
+
+    if (object_type == kVulkanObjectTypeImage) {
         mem_info->bound_images.insert(handle);
-    else
+    } else if (object_type == kVulkanObjectTypeBuffer) {
         mem_info->bound_buffers.insert(handle);
+    } else if (object_type == kVulkanObjectTypeAccelerationStructureNV) {
+        mem_info->bound_acceleration_structures.insert(handle);
+    } else {
+        // Unsupported object type
+        assert(false);
+    }
 }
 
 bool CoreChecks::ValidateInsertImageMemoryRange(VkImage image, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
                                                 VkMemoryRequirements mem_reqs, bool is_linear, const char *api_name) {
-    return ValidateInsertMemoryRange(HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear, api_name);
+    return ValidateInsertMemoryRange(HandleToUint64(image), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeImage, is_linear,
+                                     api_name);
 }
 void CoreChecks::InsertImageMemoryRange(VkImage image, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
                                         VkMemoryRequirements mem_reqs, bool is_linear) {
-    InsertMemoryRange(HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear);
+    InsertMemoryRange(HandleToUint64(image), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeImage, is_linear);
 }
 
 bool CoreChecks::ValidateInsertBufferMemoryRange(VkBuffer buffer, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
                                                  VkMemoryRequirements mem_reqs, const char *api_name) {
-    return ValidateInsertMemoryRange(HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
+    return ValidateInsertMemoryRange(HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeBuffer, true,
+                                     api_name);
 }
 void CoreChecks::InsertBufferMemoryRange(VkBuffer buffer, DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
                                          VkMemoryRequirements mem_reqs) {
-    InsertMemoryRange(HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true);
+    InsertMemoryRange(HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeBuffer, true);
+}
+
+bool CoreChecks::ValidateInsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, DEVICE_MEMORY_STATE *mem_info,
+                                                                VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs,
+                                                                const char *api_name) {
+    return ValidateInsertMemoryRange(HandleToUint64(as), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeAccelerationStructureNV,
+                                     true, api_name);
+}
+void CoreChecks::InsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, DEVICE_MEMORY_STATE *mem_info,
+                                                        VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs) {
+    InsertMemoryRange(HandleToUint64(as), mem_info, mem_offset, mem_reqs, kVulkanObjectTypeAccelerationStructureNV, true);
 }
 
 // Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
 //  is_image indicates if handle is for image or buffer
 //  This function will also remove the handle-to-index mapping from the appropriate
 //  map and clean up any aliases for range being removed.
-static void RemoveMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info, bool is_image) {
+static void RemoveMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info, VulkanObjectType object_type) {
     auto erase_range = &mem_info->bound_ranges[handle];
     for (auto alias_range : erase_range->aliases) {
         alias_range->aliases.erase(erase_range);
     }
     erase_range->aliases.clear();
     mem_info->bound_ranges.erase(handle);
-    if (is_image) {
+    if (object_type == kVulkanObjectTypeImage) {
         mem_info->bound_images.erase(handle);
-    } else {
+    } else if (object_type == kVulkanObjectTypeBuffer) {
         mem_info->bound_buffers.erase(handle);
+    } else if (object_type == kVulkanObjectTypeAccelerationStructureNV) {
+        mem_info->bound_acceleration_structures.erase(handle);
+    } else {
+        // Unsupported object type
+        assert(false);
     }
 }
 
 void ValidationStateTracker::RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info) {
-    RemoveMemoryRange(handle, mem_info, false);
+    RemoveMemoryRange(handle, mem_info, kVulkanObjectTypeBuffer);
 }
 
 void ValidationStateTracker::RemoveImageMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info) {
-    RemoveMemoryRange(handle, mem_info, true);
+    RemoveMemoryRange(handle, mem_info, kVulkanObjectTypeImage);
+}
+
+void ValidationStateTracker::RemoveAccelerationStructureMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE *mem_info) {
+    RemoveMemoryRange(handle, mem_info, kVulkanObjectTypeAccelerationStructureNV);
 }
 
 bool CoreChecks::ValidateMemoryTypes(const DEVICE_MEMORY_STATE *mem_info, const uint32_t memory_type_bits, const char *funcName,
@@ -6459,6 +6538,387 @@
     cb_state->status |= CBSTATUS_SHADING_RATE_PALETTE_SET;
 }
 
+void CoreChecks::PostCallRecordCreateAccelerationStructureNV(VkDevice device,
+                                                             const VkAccelerationStructureCreateInfoNV *pCreateInfo,
+                                                             const VkAllocationCallbacks *pAllocator,
+                                                             VkAccelerationStructureNV *pAccelerationStructure, VkResult result) {
+    if (VK_SUCCESS != result) return;
+    std::unique_ptr<ACCELERATION_STRUCTURE_STATE> as_state(new ACCELERATION_STRUCTURE_STATE(*pAccelerationStructure, pCreateInfo));
+    accelerationStructureMap[*pAccelerationStructure] = std::move(as_state);
+}
+
+void CoreChecks::PostCallRecordGetAccelerationStructureMemoryRequirementsNV(
+    VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) {
+    ACCELERATION_STRUCTURE_STATE *as_state = GetAccelerationStructureState(pInfo->accelerationStructure);
+    if (as_state != nullptr) {
+        if (pInfo->type == VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV) {
+            as_state->memory_requirements = *pMemoryRequirements;
+            as_state->memory_requirements_checked = true;
+        } else if (pInfo->type == VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV) {
+            as_state->build_scratch_memory_requirements = *pMemoryRequirements;
+            as_state->build_scratch_memory_requirements_checked = true;
+        } else if (pInfo->type == VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV) {
+            as_state->update_scratch_memory_requirements = *pMemoryRequirements;
+            as_state->update_scratch_memory_requirements_checked = true;
+        }
+    }
+}
+
+bool CoreChecks::PreCallValidateBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount,
+                                                                  const VkBindAccelerationStructureMemoryInfoNV *pBindInfos) {
+    bool skip = false;
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        const VkBindAccelerationStructureMemoryInfoNV &info = pBindInfos[i];
+
+        ACCELERATION_STRUCTURE_STATE *as_state = GetAccelerationStructureState(info.accelerationStructure);
+        if (!as_state) {
+            continue;
+        }
+        uint64_t as_handle = HandleToUint64(info.accelerationStructure);
+        if (!as_state->GetBoundMemory().empty()) {
+            skip |= log_msg(
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, as_handle,
+                "VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-02450",
+                "vkBindAccelerationStructureMemoryNV(): accelerationStructure must not already be backed by a memory object.");
+        }
+
+        if (!as_state->memory_requirements_checked) {
+            VkAccelerationStructureMemoryRequirementsInfoNV as_memory_requirements_info = {};
+            as_memory_requirements_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
+            as_memory_requirements_info.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
+            as_memory_requirements_info.accelerationStructure = as_state->acceleration_structure;
+            DispatchGetAccelerationStructureMemoryRequirementsNV(device, &as_memory_requirements_info,
+                                                                 &as_state->memory_requirements);
+            as_state->memory_requirements_checked = true;
+        }
+
+        // Validate bound memory range information
+        const auto mem_info = GetDevMemState(info.memory);
+        if (mem_info) {
+            skip |= ValidateInsertAccelerationStructureMemoryRange(info.accelerationStructure, mem_info, info.memoryOffset,
+                                                                   as_state->memory_requirements.memoryRequirements,
+                                                                   "vkBindAccelerationStructureMemoryNV()");
+            skip |= ValidateMemoryTypes(mem_info, as_state->memory_requirements.memoryRequirements.memoryTypeBits,
+                                        "vkBindAccelerationStructureMemoryNV()",
+                                        "VUID-VkBindAccelerationStructureMemoryInfoNV-memory-02593");
+        }
+
+        // Validate memory requirements alignment
+        if (SafeModulo(info.memoryOffset, as_state->memory_requirements.memoryRequirements.alignment) != 0) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT,
+                            as_handle, "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02594",
+                            "vkBindAccelerationStructureMemoryNV(): memoryOffset is 0x%" PRIxLEAST64
+                            " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
+                            ", returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure"
+                            "and type of VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV.",
+                            info.memoryOffset, as_state->memory_requirements.memoryRequirements.alignment);
+        }
+
+        if (mem_info) {
+            // Validate memory requirements size
+            if (as_state->memory_requirements.memoryRequirements.size > (mem_info->alloc_info.allocationSize - info.memoryOffset)) {
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, as_handle,
+                    "VUID-VkBindAccelerationStructureMemoryInfoNV-size-02595",
+                    "vkBindAccelerationStructureMemoryNV(): memory size minus memoryOffset is 0x%" PRIxLEAST64
+                    " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
+                    ", returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure"
+                    "and type of VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV.",
+                    mem_info->alloc_info.allocationSize - info.memoryOffset, as_state->memory_requirements.memoryRequirements.size);
+            }
+        }
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount,
+                                                                 const VkBindAccelerationStructureMemoryInfoNV *pBindInfos,
+                                                                 VkResult result) {
+    if (VK_SUCCESS != result) return;
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        const VkBindAccelerationStructureMemoryInfoNV &info = pBindInfos[i];
+
+        ACCELERATION_STRUCTURE_STATE *as_state = GetAccelerationStructureState(info.accelerationStructure);
+        if (as_state) {
+            // Track bound memory range information
+            auto mem_info = GetDevMemState(info.memory);
+            if (mem_info) {
+                if (!as_state->memory_requirements_checked) {
+                    VkAccelerationStructureMemoryRequirementsInfoNV as_memory_requirements_info = {};
+                    as_memory_requirements_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
+                    as_memory_requirements_info.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
+                    as_memory_requirements_info.accelerationStructure = as_state->acceleration_structure;
+                    DispatchGetAccelerationStructureMemoryRequirementsNV(device, &as_memory_requirements_info,
+                                                                         &as_state->memory_requirements);
+                    as_state->memory_requirements_checked = true;
+                }
+
+                InsertAccelerationStructureMemoryRange(info.accelerationStructure, mem_info, info.memoryOffset,
+                                                       as_state->requirements);
+            }
+            // Track objects tied to memory
+            SetMemBinding(info.memory, as_state, info.memoryOffset,
+                          VulkanTypedHandle(info.accelerationStructure, kVulkanObjectTypeAccelerationStructureNV));
+        }
+    }
+}
+
+bool CoreChecks::PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,
+                                                                const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData,
+                                                                VkDeviceSize instanceOffset, VkBool32 update,
+                                                                VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
+                                                                VkBuffer scratch, VkDeviceSize scratchOffset) {
+    CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(cb_state, "vkCmdBuildAccelerationStructureNV()", VK_QUEUE_COMPUTE_BIT,
+                                      "VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-cmdpool");
+
+    skip |= ValidateCmd(cb_state, CMD_BUILDACCELERATIONSTRUCTURENV, "vkCmdBuildAccelerationStructureNV()");
+
+    if (pInfo != nullptr && pInfo->geometryCount > phys_dev_ext_props.ray_tracing_props.maxGeometryCount) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-geometryCount-02241",
+                        "vkCmdBuildAccelerationStructureNV(): geometryCount [%d] must be less than or equal to "
+                        "VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount.",
+                        pInfo->geometryCount);
+    }
+
+    ACCELERATION_STRUCTURE_STATE *dst_as_state = GetAccelerationStructureState(dst);
+    ACCELERATION_STRUCTURE_STATE *src_as_state = GetAccelerationStructureState(src);
+    BUFFER_STATE *scratch_buffer_state = GetBufferState(scratch);
+
+    if (dst_as_state != nullptr && pInfo != nullptr) {
+        if (dst_as_state->create_info.info.type != pInfo->type) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                            "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::type"
+                            "[%s] must be identical to build info VkAccelerationStructureInfoNV::type [%s].",
+                            string_VkAccelerationStructureTypeNV(dst_as_state->create_info.info.type),
+                            string_VkAccelerationStructureTypeNV(pInfo->type));
+        }
+        if (dst_as_state->create_info.info.flags != pInfo->flags) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                            "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::flags"
+                            "[0x%X] must be identical to build info VkAccelerationStructureInfoNV::flags [0x%X].",
+                            dst_as_state->create_info.info.flags, pInfo->flags);
+        }
+        if (dst_as_state->create_info.info.instanceCount < pInfo->instanceCount) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                            "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::instanceCount "
+                            "[%d] must be greater than or equal to build info VkAccelerationStructureInfoNV::instanceCount [%d].",
+                            dst_as_state->create_info.info.instanceCount, pInfo->instanceCount);
+        }
+        if (dst_as_state->create_info.info.geometryCount < pInfo->geometryCount) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                            "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::geometryCount"
+                            "[%d] must be greater than or equal to build info VkAccelerationStructureInfoNV::geometryCount [%d].",
+                            dst_as_state->create_info.info.geometryCount, pInfo->geometryCount);
+        } else {
+            for (uint32_t i = 0; i < pInfo->geometryCount; i++) {
+                const VkGeometryDataNV &create_geometry_data = dst_as_state->create_info.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 |= log_msg(
+                        report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                        "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.triangles.vertexCount [%d]"
+                        "must be greater than or equal to build info pGeometries[%d].geometry.triangles.vertexCount [%d].",
+                        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 |= log_msg(
+                        report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                        "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.triangles.indexCount [%d]"
+                        "must be greater than or equal to build info pGeometries[%d].geometry.triangles.indexCount [%d].",
+                        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 |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                    HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
+                                    "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.aabbs.numAABBs [%d]"
+                                    "must be greater than or equal to build info pGeometries[%d].geometry.aabbs.numAABBs [%d].",
+                                    i, create_geometry_data.aabbs.numAABBs, i, build_geometry_data.aabbs.numAABBs);
+                    break;
+                }
+            }
+        }
+    }
+
+    if (dst_as_state != nullptr) {
+        skip |= ValidateMemoryIsBoundToAccelerationStructure(
+            dst_as_state, "vkCmdBuildAccelerationStructureNV()",
+            "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkAccelerationStructureNV");
+    }
+
+    if (update == VK_TRUE) {
+        if (src == VK_NULL_HANDLE) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-update-02489",
+                            "vkCmdBuildAccelerationStructureNV(): 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 |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-update-02489",
+                                "vkCmdBuildAccelerationStructureNV(): 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) {
+            VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo = {};
+            memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
+            memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV;
+            memoryRequirementsInfo.accelerationStructure = dst;
+            DispatchGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo,
+                                                                 &dst_as_state->update_scratch_memory_requirements);
+            dst_as_state->update_scratch_memory_requirements_checked = true;
+        }
+        if (scratch_buffer_state != nullptr && dst_as_state != nullptr &&
+            dst_as_state->update_scratch_memory_requirements_checked &&
+            dst_as_state->update_scratch_memory_requirements.memoryRequirements.size >
+                (scratch_buffer_state->binding.size - (scratch_buffer_state->binding.offset + scratchOffset))) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-update-02492",
+                            "vkCmdBuildAccelerationStructureNV(): 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) {
+            VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo = {};
+            memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
+            memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV;
+            memoryRequirementsInfo.accelerationStructure = dst;
+            DispatchGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo,
+                                                                 &dst_as_state->build_scratch_memory_requirements);
+            dst_as_state->build_scratch_memory_requirements_checked = true;
+        }
+        if (scratch_buffer_state != nullptr && dst_as_state != nullptr && dst_as_state->build_scratch_memory_requirements_checked &&
+            dst_as_state->build_scratch_memory_requirements.memoryRequirements.size >
+                (scratch_buffer_state->binding.size - (scratch_buffer_state->binding.offset + scratchOffset))) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdBuildAccelerationStructureNV-update-02491",
+                            "vkCmdBuildAccelerationStructureNV(): 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");
+        }
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,
+                                                               const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData,
+                                                               VkDeviceSize instanceOffset, VkBool32 update,
+                                                               VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
+                                                               VkBuffer scratch, VkDeviceSize scratchOffset) {
+    CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
+    if (cb_state) {
+        ACCELERATION_STRUCTURE_STATE *dst_as_state = GetAccelerationStructureState(dst);
+        ACCELERATION_STRUCTURE_STATE *src_as_state = GetAccelerationStructureState(src);
+        if (dst_as_state != nullptr) {
+            dst_as_state->built = true;
+            dst_as_state->build_info.initialize(pInfo);
+            AddCommandBufferBindingAccelerationStructure(cb_state, dst_as_state);
+        }
+        if (src_as_state != nullptr) {
+            AddCommandBufferBindingAccelerationStructure(cb_state, src_as_state);
+        }
+    }
+}
+
+bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst,
+                                                               VkAccelerationStructureNV src,
+                                                               VkCopyAccelerationStructureModeNV mode) {
+    CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(cb_state, "vkCmdCopyAccelerationStructureNV()", VK_QUEUE_COMPUTE_BIT,
+                                      "VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-cmdpool");
+
+    skip |= ValidateCmd(cb_state, CMD_COPYACCELERATIONSTRUCTURENV, "vkCmdCopyAccelerationStructureNV()");
+
+    ACCELERATION_STRUCTURE_STATE *dst_as_state = GetAccelerationStructureState(dst);
+    ACCELERATION_STRUCTURE_STATE *src_as_state = GetAccelerationStructureState(src);
+
+    if (dst_as_state != nullptr) {
+        skip |= ValidateMemoryIsBoundToAccelerationStructure(
+            dst_as_state, "vkCmdBuildAccelerationStructureNV()",
+            "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkAccelerationStructureNV");
+    }
+
+    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 |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdCopyAccelerationStructureNV-src-02497",
+                            "vkCmdCopyAccelerationStructureNV(): src must have been built with "
+                            "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV if mode is "
+                            "VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV.");
+        }
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst,
+                                                              VkAccelerationStructureNV src,
+                                                              VkCopyAccelerationStructureModeNV mode) {
+    CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
+    if (cb_state) {
+        ACCELERATION_STRUCTURE_STATE *src_as_state = GetAccelerationStructureState(src);
+        ACCELERATION_STRUCTURE_STATE *dst_as_state = GetAccelerationStructureState(dst);
+        if (dst_as_state != nullptr && src_as_state != nullptr) {
+            dst_as_state->built = true;
+            dst_as_state->build_info = src_as_state->build_info;
+            AddCommandBufferBindingAccelerationStructure(cb_state, dst_as_state);
+            AddCommandBufferBindingAccelerationStructure(cb_state, src_as_state);
+        }
+    }
+}
+
+bool CoreChecks::PreCallValidateDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
+                                                               const VkAllocationCallbacks *pAllocator) {
+    ACCELERATION_STRUCTURE_STATE *as_state = GetAccelerationStructureState(accelerationStructure);
+    const VulkanTypedHandle obj_struct(accelerationStructure, kVulkanObjectTypeAccelerationStructureNV);
+    bool skip = false;
+    if (as_state) {
+        skip |= ValidateObjectNotInUse(as_state, obj_struct, "vkDestroyAccelerationStructureNV",
+                                       "VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02442");
+    }
+    return skip;
+}
+
+void CoreChecks::PreCallRecordDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
+                                                             const VkAllocationCallbacks *pAllocator) {
+    if (!accelerationStructure) return;
+    auto *as_state = GetAccelerationStructureState(accelerationStructure);
+    if (as_state) {
+        const VulkanTypedHandle obj_struct(accelerationStructure, kVulkanObjectTypeAccelerationStructureNV);
+        InvalidateCommandBuffers(as_state->cb_bindings, obj_struct);
+        for (auto mem_binding : as_state->GetBoundMemory()) {
+            auto mem_info = GetDevMemState(mem_binding);
+            if (mem_info) {
+                RemoveAccelerationStructureMemoryRange(HandleToUint64(accelerationStructure), mem_info);
+            }
+        }
+        ClearMemoryObjectBindings(obj_struct);
+        accelerationStructureMap.erase(accelerationStructure);
+    }
+}
+
 bool CoreChecks::PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
     const CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
     assert(cb_state);
diff --git a/layers/core_validation.h b/layers/core_validation.h
index ab07e99..7d7ce70 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -243,6 +243,7 @@
     VALSTATETRACK_MAP_AND_TRAITS(VkFence, FENCE_STATE, fenceMap)
     VALSTATETRACK_MAP_AND_TRAITS(VkQueryPool, QUERY_POOL_STATE, queryPoolMap)
     VALSTATETRACK_MAP_AND_TRAITS(VkSemaphore, SEMAPHORE_STATE, semaphoreMap)
+    VALSTATETRACK_MAP_AND_TRAITS(VkAccelerationStructureNV, ACCELERATION_STRUCTURE_STATE, accelerationStructureMap)
     VALSTATETRACK_MAP_AND_TRAITS_INSTANCE_SCOPE(VkSurfaceKHR, SURFACE_STATE, surface_map)
 
    public:
@@ -321,6 +322,12 @@
     QUERY_POOL_STATE* GetQueryPoolState(VkQueryPool query_pool) { return Get<QUERY_POOL_STATE>(query_pool); }
     const SEMAPHORE_STATE* GetSemaphoreState(VkSemaphore semaphore) const { return Get<SEMAPHORE_STATE>(semaphore); }
     SEMAPHORE_STATE* GetSemaphoreState(VkSemaphore semaphore) { return Get<SEMAPHORE_STATE>(semaphore); }
+    const ACCELERATION_STRUCTURE_STATE* GetAccelerationStructureState(VkAccelerationStructureNV as) const {
+        return Get<ACCELERATION_STRUCTURE_STATE>(as);
+    }
+    ACCELERATION_STRUCTURE_STATE* GetAccelerationStructureState(VkAccelerationStructureNV as) {
+        return Get<ACCELERATION_STRUCTURE_STATE>(as);
+    }
     const SURFACE_STATE* GetSurfaceState(VkSurfaceKHR surface) const { return Get<SURFACE_STATE>(surface); }
     SURFACE_STATE* GetSurfaceState(VkSurfaceKHR surface) { return Get<SURFACE_STATE>(surface); }
 
@@ -505,6 +512,7 @@
                                    PIPELINE_STATE::StageState* stage_state);
     void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE* mem_info);
     void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE* mem_info);
+    void RemoveAccelerationStructureMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE* mem_info);
 
     DeviceFeatures enabled_features = {};
     // Device specific data
@@ -524,6 +532,7 @@
         VkPhysicalDeviceCooperativeMatrixPropertiesNV cooperative_matrix_props;
         VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback_props;
         VkPhysicalDeviceSubgroupProperties subgroup_props;
+        VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props;
     };
     DeviceExtensionProperties phys_dev_ext_props = {};
     std::vector<VkCooperativeMatrixPropertiesNV> cooperative_matrix_properties;
@@ -722,9 +731,10 @@
                                     SURFACE_STATE* surface_state, SWAPCHAIN_NODE* old_swapchain_state);
     void RecordVulkanSurface(VkSurfaceKHR* pSurface);
     bool ValidateInsertMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE* mem_info, VkDeviceSize memoryOffset,
-                                   VkMemoryRequirements memRequirements, bool is_image, bool is_linear, const char* api_name);
+                                   VkMemoryRequirements memRequirements, VulkanObjectType object_type, bool is_linear,
+                                   const char* api_name);
     void InsertMemoryRange(uint64_t handle, DEVICE_MEMORY_STATE* mem_info, VkDeviceSize memoryOffset,
-                           VkMemoryRequirements memRequirements, bool is_image, bool is_linear);
+                           VkMemoryRequirements memRequirements, VulkanObjectType object_type, bool is_linear);
     bool ValidateInsertImageMemoryRange(VkImage image, DEVICE_MEMORY_STATE* mem_info, VkDeviceSize mem_offset,
                                         VkMemoryRequirements mem_reqs, bool is_linear, const char* api_name);
     void InsertImageMemoryRange(VkImage image, DEVICE_MEMORY_STATE* mem_info, VkDeviceSize mem_offset,
@@ -733,6 +743,12 @@
                                          VkMemoryRequirements mem_reqs, const char* api_name);
     void InsertBufferMemoryRange(VkBuffer buffer, DEVICE_MEMORY_STATE* mem_info, VkDeviceSize mem_offset,
                                  VkMemoryRequirements mem_reqs);
+    bool ValidateInsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, DEVICE_MEMORY_STATE* mem_info,
+                                                        VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs,
+                                                        const char* api_name);
+    void InsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, DEVICE_MEMORY_STATE* mem_info,
+                                                VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs);
+
     bool ValidateMemoryTypes(const DEVICE_MEMORY_STATE* mem_info, const uint32_t memory_type_bits, const char* funcName,
                              const char* msgCode);
     bool ValidateCommandBufferState(CMD_BUFFER_STATE* cb_state, const char* call_source, int current_submit_count,
@@ -760,8 +776,10 @@
                                                  VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
     bool ValidateMemoryIsBoundToBuffer(const BUFFER_STATE*, const char*, const char*) const;
     bool ValidateMemoryIsBoundToImage(const IMAGE_STATE*, const char*, const char*) const;
+    bool ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE*, const char*, const char*) const;
     void AddCommandBufferBindingSampler(CMD_BUFFER_STATE*, SAMPLER_STATE*);
     void AddCommandBufferBindingImageView(CMD_BUFFER_STATE*, IMAGE_VIEW_STATE*);
+    void AddCommandBufferBindingAccelerationStructure(CMD_BUFFER_STATE*, ACCELERATION_STRUCTURE_STATE*);
     bool ValidateObjectNotInUse(const BASE_NODE* obj_node, const VulkanTypedHandle& obj_struct, const char* caller_name,
                                 const char* error_code) const;
     bool ValidateCmdQueueFlags(const CMD_BUFFER_STATE* cb_node, const char* caller_name, VkQueueFlags flags,
@@ -1414,6 +1432,33 @@
     bool PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
                                                            uint32_t viewportCount,
                                                            const VkShadingRatePaletteNV* pShadingRatePalettes);
+    void PostCallRecordCreateAccelerationStructureNV(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo,
+                                                     const VkAllocationCallbacks* pAllocator,
+                                                     VkAccelerationStructureNV* pAccelerationStructure, VkResult result);
+    void PostCallRecordGetAccelerationStructureMemoryRequirementsNV(VkDevice device,
+                                                                    const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
+                                                                    VkMemoryRequirements2KHR* pMemoryRequirements);
+    bool PreCallValidateBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount,
+                                                          const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
+    void PostCallRecordBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount,
+                                                         const VkBindAccelerationStructureMemoryInfoNV* pBindInfos,
+                                                         VkResult result);
+    bool PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo,
+                                                        VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update,
+                                                        VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
+                                                        VkBuffer scratch, VkDeviceSize scratchOffset);
+    void PostCallRecordCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo,
+                                                       VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update,
+                                                       VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
+                                                       VkBuffer scratch, VkDeviceSize scratchOffset);
+    bool PreCallValidateCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst,
+                                                       VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode);
+    void PostCallRecordCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst,
+                                                      VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode);
+    bool PreCallValidateDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
+                                                       const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
+                                                     const VkAllocationCallbacks* pAllocator);
     bool PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth);
     bool PreCallValidateCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
                                         float depthBiasSlopeFactor);
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 79c9b72..885008f 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -332,6 +332,27 @@
     IMAGE_VIEW_STATE(const IMAGE_VIEW_STATE &rh_obj) = delete;
 };
 
+class ACCELERATION_STRUCTURE_STATE : public BINDABLE {
+   public:
+    VkAccelerationStructureNV acceleration_structure;
+    safe_VkAccelerationStructureCreateInfoNV create_info;
+    bool memory_requirements_checked = false;
+    VkMemoryRequirements2KHR memory_requirements;
+    bool build_scratch_memory_requirements_checked = false;
+    VkMemoryRequirements2KHR build_scratch_memory_requirements;
+    bool update_scratch_memory_requirements_checked = false;
+    VkMemoryRequirements2KHR update_scratch_memory_requirements;
+    bool built = false;
+    safe_VkAccelerationStructureInfoNV build_info;
+    ACCELERATION_STRUCTURE_STATE(VkAccelerationStructureNV as, const VkAccelerationStructureCreateInfoNV *ci)
+        : acceleration_structure(as),
+          create_info(ci),
+          memory_requirements{},
+          build_scratch_memory_requirements_checked{},
+          update_scratch_memory_requirements_checked{} {}
+    ACCELERATION_STRUCTURE_STATE(const ACCELERATION_STRUCTURE_STATE &rh_obj) = delete;
+};
+
 struct MemRange {
     VkDeviceSize offset;
     VkDeviceSize size;
@@ -369,9 +390,10 @@
     VkExternalMemoryHandleTypeFlags export_handle_type_flags;
     std::unordered_set<VulkanTypedHandle> obj_bindings;       // objects bound to this memory
     std::unordered_map<uint64_t, MEMORY_RANGE> bound_ranges;  // Map of object to its binding range
-    // Convenience vectors image/buff handles to speed up iterating over images or buffers independently
+    // Convenience vectors of handles to speed up iterating over objects independently
     std::unordered_set<uint64_t> bound_images;
     std::unordered_set<uint64_t> bound_buffers;
+    std::unordered_set<uint64_t> bound_acceleration_structures;
 
     MemRange mem_range;
     void *shadow_copy_base;    // Base of layer's allocation for guard band, data, and alignment space
diff --git a/layers/generated/parameter_validation.cpp b/layers/generated/parameter_validation.cpp
index 411c719..8da06e1 100644
--- a/layers/generated/parameter_validation.cpp
+++ b/layers/generated/parameter_validation.cpp
@@ -9383,6 +9383,7 @@
     skip |= validate_bool32("vkCmdBuildAccelerationStructureNV", "update", update);
     skip |= validate_required_handle("vkCmdBuildAccelerationStructureNV", "dst", dst);
     skip |= validate_required_handle("vkCmdBuildAccelerationStructureNV", "scratch", scratch);
+    skip |= manual_PreCallValidateCmdBuildAccelerationStructureNV(commandBuffer, pInfo, instanceData, instanceOffset, update, dst, src, scratch, scratchOffset);
     return skip;
 }
 
@@ -9547,6 +9548,7 @@
     if (!device_extensions.vk_nv_ray_tracing) skip |= OutputExtensionError("vkGetAccelerationStructureHandleNV", VK_NV_RAY_TRACING_EXTENSION_NAME);
     skip |= validate_required_handle("vkGetAccelerationStructureHandleNV", "accelerationStructure", accelerationStructure);
     skip |= validate_array("vkGetAccelerationStructureHandleNV", "dataSize", "pData", dataSize, &pData, true, true, "VUID-vkGetAccelerationStructureHandleNV-dataSize-arraylength", "VUID-vkGetAccelerationStructureHandleNV-pData-parameter");
+    skip |= manual_PreCallValidateGetAccelerationStructureHandleNV(device, accelerationStructure, dataSize, pData);
     return skip;
 }
 
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index 5be2974..3ed6157 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -146,6 +146,14 @@
         phys_dev_ext_props.mesh_shader_props = mesh_shader_props;
     }
 
+    if (device_extensions.vk_nv_ray_tracing) {
+        // Get the needed ray tracing limits
+        auto ray_tracing_props = lvl_init_struct<VkPhysicalDeviceRayTracingPropertiesNV>();
+        auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&ray_tracing_props);
+        DispatchGetPhysicalDeviceProperties2KHR(physicalDevice, &prop2);
+        phys_dev_ext_props.ray_tracing_props = ray_tracing_props;
+    }
+
     stateless_validation->phys_dev_ext_props = this->phys_dev_ext_props;
 
     // Save app-enabled features in this device's validation object
@@ -2996,6 +3004,58 @@
     return skip;
 }
 
+bool StatelessValidation::ValidateAccelerationStructureInfoNV(const VkAccelerationStructureInfoNV &info) {
+    bool skip = false;
+    if (info.type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV && info.geometryCount != 0) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, 0,
+                        "VUID-VkAccelerationStructureInfoNV-type-02425",
+                        "VkAccelerationStructureInfoNV: If type is VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV then "
+                        "geometryCount must be 0.");
+    }
+    if (info.type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV && info.instanceCount != 0) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, 0,
+                        "VUID-VkAccelerationStructureInfoNV-type-02426",
+                        "VkAccelerationStructureInfoNV: If type is VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV then "
+                        "instanceCount must be 0.");
+    }
+    if (info.flags & VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV &&
+        info.flags & VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, 0,
+                        "VUID-VkAccelerationStructureInfoNV-flags-02592",
+                        "VkAccelerationStructureInfoNV: If flags has the VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV"
+                        "bit set, then it must not have the VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV bit set.");
+    }
+    if (info.geometryCount > phys_dev_ext_props.ray_tracing_props.maxGeometryCount) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, 0,
+                        "VUID-VkAccelerationStructureInfoNV-geometryCount-02422",
+                        "VkAccelerationStructureInfoNV: geometryCount must be less than or equal to "
+                        "VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount.");
+    }
+    if (info.instanceCount > phys_dev_ext_props.ray_tracing_props.maxInstanceCount) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT, 0,
+                        "VUID-VkAccelerationStructureInfoNV-instanceCount-02423",
+                        "VkAccelerationStructureInfoNV: instanceCount must be less than or equal to "
+                        "VkPhysicalDeviceRayTracingPropertiesNV::maxInstanceCount.");
+    }
+    if (info.geometryCount > 0) {
+        uint64_t total_triangle_count = 0;
+        for (uint32_t i = 0; i < info.geometryCount; i++) {
+            const VkGeometryNV &geometry = info.pGeometries[i];
+            if (geometry.geometryType != VK_GEOMETRY_TYPE_TRIANGLES_NV) {
+                continue;
+            }
+            total_triangle_count += geometry.geometry.triangles.indexCount / 3;
+        }
+        if (total_triangle_count > phys_dev_ext_props.ray_tracing_props.maxTriangleCount) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT,
+                            0, "VUID-VkAccelerationStructureInfoNV-maxTriangleCount-02424",
+                            "VkAccelerationStructureInfoNV: The total number of triangles in all geometries must be less than "
+                            "or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxTriangleCount.");
+        }
+    }
+    return skip;
+}
+
 bool StatelessValidation::manual_PreCallValidateCreateAccelerationStructureNV(
     VkDevice device, const VkAccelerationStructureCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator,
     VkAccelerationStructureNV *pAccelerationStructure) {
@@ -3010,11 +3070,37 @@
                             ") with info.geometryCount (%" PRIu32 ") or info.instanceCount (%" PRIu32 ") nonzero.",
                             pCreateInfo->compactedSize, pCreateInfo->info.geometryCount, pCreateInfo->info.instanceCount);
         }
+
+        skip |= ValidateAccelerationStructureInfoNV(pCreateInfo->info);
     }
 
     return skip;
 }
 
+bool StatelessValidation::manual_PreCallValidateCmdBuildAccelerationStructureNV(
+    VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset,
+    VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset) {
+    bool skip = false;
+
+    if (pInfo != nullptr) {
+        skip |= ValidateAccelerationStructureInfoNV(*pInfo);
+    }
+
+    return skip;
+}
+
+bool StatelessValidation::manual_PreCallValidateGetAccelerationStructureHandleNV(VkDevice device,
+                                                                                 VkAccelerationStructureNV accelerationStructure,
+                                                                                 size_t dataSize, void *pData) {
+    bool skip = false;
+    if (dataSize < 8) {
+        skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT,
+                       HandleToUint64(accelerationStructure), "VUID-vkGetAccelerationStructureHandleNV-dataSize-02240",
+                       "vkGetAccelerationStructureHandleNV(): dataSize must be greater than or equal to 8.");
+    }
+    return skip;
+}
+
 bool StatelessValidation::manual_PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache,
                                                                             uint32_t createInfoCount,
                                                                             const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
diff --git a/layers/stateless_validation.h b/layers/stateless_validation.h
index ae4aea2..7f0bd57 100644
--- a/layers/stateless_validation.h
+++ b/layers/stateless_validation.h
@@ -97,6 +97,7 @@
     struct DeviceExtensionProperties {
         VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
         VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
+        VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props;
     };
     DeviceExtensionProperties phys_dev_ext_props = {};
 
@@ -899,6 +900,8 @@
     bool ValidateDeviceQueueFamily(uint32_t queue_family, const char *cmd_name, const char *parameter_name,
                                    const std::string &error_code, bool optional);
 
+    bool ValidateAccelerationStructureInfoNV(const VkAccelerationStructureInfoNV &info);
+
     bool OutputExtensionError(const std::string &api_name, const std::string &extension_name);
 
     void PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
@@ -949,7 +952,7 @@
     bool manual_PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
                                                     const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
                                                     const VkCopyDescriptorSet *pDescriptorCopies);
-    ;
+
     bool manual_PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
                                                   const VkDescriptorSet *pDescriptorSets);
 
@@ -1051,6 +1054,13 @@
                                                              const VkAccelerationStructureCreateInfoNV *pCreateInfo,
                                                              const VkAllocationCallbacks *pAllocator,
                                                              VkAccelerationStructureNV *pAccelerationStructure);
+    bool manual_PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,
+                                                               const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData,
+                                                               VkDeviceSize instanceOffset, VkBool32 update,
+                                                               VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
+                                                               VkBuffer scratch, VkDeviceSize scratchOffset);
+    bool manual_PreCallValidateGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
+                                                                size_t dataSize, void *pData);
     bool manual_PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
                                                            const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
                                                            const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);