/*
 * Copyright (c) 2015-2026 The Khronos Group Inc.
 * Copyright (c) 2015-2026 Valve Corporation
 * Copyright (c) 2015-2026 LunarG, Inc.
 * Copyright (c) 2015-2026 Google, Inc.
 * Modifications Copyright (C) 2020 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
 */

#include "layer_validation_tests.h"
#include "ray_tracing_objects.h"
#include "descriptor_helper.h"
#include "shader_helper.h"
#include "utils/math_utils.h"

// Compute a binomial coefficient
template <typename T>
constexpr T binom(T n, T k) {
    static_assert(std::numeric_limits<T>::is_integer, "Unsigned integer required.");
    static_assert(std::is_unsigned<T>::value, "Unsigned integer required.");
    assert(n >= k);
    if (n == 0) {
        return 0;
    }
    if (k == 0) {
        return 1;
    }

    T numerator = 1;
    T denominator = 1;
    for (T i = 1; i <= k; ++i) {
        numerator *= n - i + 1;
        denominator *= i;
    }

    return numerator / denominator;
}

class NegativeRayTracing : public RayTracingTest {};

TEST_F(NegativeRayTracing, BarrierAccessAccelerationStructure) {
    TEST_DESCRIPTION("Test barrier with access ACCELERATION_STRUCTURE bit.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::synchronization2);
    RETURN_IF_SKIP(Init());

    VkMemoryBarrier2 mem_barrier = vku::InitStructHelper();
    mem_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
    mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;

    m_command_buffer.Begin();

    mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT;
    mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-srcAccessMask-03928");
    m_command_buffer.BarrierKHR(mem_barrier);

    mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-srcStageMask-10751");
    m_command_buffer.BarrierKHR(mem_barrier);

    mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
    mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
    mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-dstAccessMask-03928");
    m_command_buffer.BarrierKHR(mem_barrier);

    m_command_buffer.End();

    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BarrierReadAccelerationStructureRayQueryEnabled) {
    TEST_DESCRIPTION("Test barrier with VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR and ray query eanbled.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::synchronization2);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    VkMemoryBarrier2 mem_barrier{};

    m_command_buffer.Begin();

    mem_barrier = vku::InitStructHelper();
    mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-srcAccessMask-03927");
    m_command_buffer.BarrierKHR(mem_barrier);
    m_errorMonitor->VerifyFound();

    mem_barrier = vku::InitStructHelper();
    mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-dstAccessMask-03927");
    m_command_buffer.BarrierKHR(mem_barrier);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, BarrierSync2AccessAccelerationStructureRayQueryDisabled) {
    TEST_DESCRIPTION(
        "Test sync2 barrier with ACCELERATION_STRUCTURE_READ memory access."
        "Ray query feature is not enabled.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::synchronization2);
    RETURN_IF_SKIP(Init());

    VkMemoryBarrier2 mem_barrier = vku::InitStructHelper();
    mem_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
    mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;

    vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);

    VkBufferMemoryBarrier2 buffer_barrier = vku::InitStructHelper();
    buffer_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
    buffer_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
    buffer_barrier.buffer = buffer;
    buffer_barrier.size = 32;

    vkt::Image image(*m_device, 128, 128, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);

    VkImageMemoryBarrier2 image_barrier = vku::InitStructHelper();
    image_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
    image_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
    image_barrier.image = image;
    image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};

    VkDependencyInfo dependency_info = vku::InitStructHelper();
    dependency_info.memoryBarrierCount = 1;
    dependency_info.pMemoryBarriers = &mem_barrier;
    dependency_info.bufferMemoryBarrierCount = 1;
    dependency_info.pBufferMemoryBarriers = &buffer_barrier;
    dependency_info.imageMemoryBarrierCount = 1;
    dependency_info.pImageMemoryBarriers = &image_barrier;

    m_command_buffer.Begin();

    mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    buffer_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    image_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    buffer_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    image_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-srcAccessMask-06256");
    m_errorMonitor->SetDesiredError("VUID-VkBufferMemoryBarrier2-srcAccessMask-06256");
    m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-srcAccessMask-06256");
    m_errorMonitor->SetDesiredError("VUID-VkMemoryBarrier2-dstAccessMask-06256");
    m_errorMonitor->SetDesiredError("VUID-VkBufferMemoryBarrier2-dstAccessMask-06256");
    m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-dstAccessMask-06256");
    vk::CmdPipelineBarrier2KHR(m_command_buffer, &dependency_info);

    m_command_buffer.End();

    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BarrierSync1AccessAccelerationStructureRayQueryDisabled) {
    TEST_DESCRIPTION(
        "Test sync1 barrier with ACCELERATION_STRUCTURE_READ memory access."
        "Ray query feature is not enabled.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(Init());

    VkMemoryBarrier memory_barrier = vku::InitStructHelper();
    memory_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    memory_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;

    vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
    VkBufferMemoryBarrier buffer_barrier = vku::InitStructHelper();
    buffer_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.buffer = buffer;
    buffer_barrier.size = VK_WHOLE_SIZE;

    vkt::Image image(*m_device, 128, 128, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);

    VkImageMemoryBarrier image_barrier = vku::InitStructHelper();
    image_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
    image_barrier.image = image;
    image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};

    m_command_buffer.Begin();

    // memory barrier
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-dstAccessMask-06257");
    // buffer barrier
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-dstAccessMask-06257");
    // image barrier
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-dstAccessMask-06257");

    vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, 0, 1,
                           &memory_barrier, 1, &buffer_barrier, 1, &image_barrier);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, EventSync1AccessAccelerationStructureRayQueryDisabled) {
    TEST_DESCRIPTION(
        "Test sync1 event wait with ACCELERATION_STRUCTURE_READ memory access."
        "Ray query feature is not enabled.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(Init());

    const vkt::Event event(*m_device);

    VkMemoryBarrier memory_barrier = vku::InitStructHelper();
    memory_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    memory_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;

    vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
    VkBufferMemoryBarrier buffer_barrier = vku::InitStructHelper();
    buffer_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    buffer_barrier.buffer = buffer;
    buffer_barrier.size = VK_WHOLE_SIZE;

    vkt::Image image(*m_device, 28, 128, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);

    VkImageMemoryBarrier image_barrier = vku::InitStructHelper();
    image_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
    image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
    image_barrier.image = image;
    image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};

    m_command_buffer.Begin();

    // memory
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-dstAccessMask-06257");
    // buffer
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-dstAccessMask-06257");
    // image
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-srcAccessMask-06257");
    m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-dstAccessMask-06257");

    vk::CmdWaitEvents(m_command_buffer, 1, &event.handle(), VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT,
                      VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, 1, &memory_barrier, 1, &buffer_barrier, 1, &image_barrier);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, DescriptorBindingUpdateAfterBindWithAccelerationStructure) {
    TEST_DESCRIPTION("Validate acceleration structure descriptor writing.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_ALL, nullptr};

    VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;

    VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper();
    flags_create_info.bindingCount = 1;
    flags_create_info.pBindingFlags = &flags;

    VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&flags_create_info);
    create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
    create_info.bindingCount = 1;
    create_info.pBindings = &binding;

    VkDescriptorSetLayout set_layout;
    m_errorMonitor->SetDesiredError(
        "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingAccelerationStructureUpdateAfterBind-03570");
    vk::CreateDescriptorSetLayout(device(), &create_info, nullptr, &set_layout);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, MaxPerStageDescriptorAccelerationStructures) {
    TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);

    // Create one descriptor set layout holding (maxPerStageDescriptorAccelerationStructures + 1) bindings
    // for the same shader stage
    const uint32_t max_accel_structs = accel_struct_props.maxPerStageDescriptorAccelerationStructures;
    if (max_accel_structs > 4096) {
        GTEST_SKIP() << "maxPerStageDescriptorAccelerationStructures is too large";
    } else if (max_accel_structs < 1) {
        GTEST_SKIP() << "maxPerStageDescriptorAccelerationStructures is 1";
    }
    std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
    dslb_vec.reserve(max_accel_structs);

    for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
        VkDescriptorSetLayoutBinding dslb = {};
        dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
        dslb.descriptorCount = 1;
        dslb.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
        dslb.binding = i;
        dslb_vec.push_back(dslb);
    }

    VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
    ds_layout_ci.bindingCount = dslb_vec.size();
    ds_layout_ci.pBindings = dslb_vec.data();

    vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
    ASSERT_TRUE(ds_layout.initialized());

    VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
    pipeline_layout_ci.setLayoutCount = 1;
    pipeline_layout_ci.pSetLayouts = &ds_layout.handle();

    m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-03571");
    // Lazy way to not query
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03573");
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
    vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, MaxPerStageDescriptorUpdateAfterBindAccelerationStructures) {
    TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);

    // Create one descriptor set layout with flag VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT holding
    // (maxPerStageDescriptorUpdateAfterBindAccelerationStructures + 1) bindings for the same shader stage
    const uint32_t max_accel_structs = accel_struct_props.maxPerStageDescriptorUpdateAfterBindAccelerationStructures;
    if (max_accel_structs > 4096) {
        GTEST_SKIP() << "maxPerStageDescriptorUpdateAfterBindAccelerationStructures is too large";
    } else if (max_accel_structs < 1) {
        GTEST_SKIP() << "maxPerStageDescriptorUpdateAfterBindAccelerationStructures is 1";
    }

    std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
    dslb_vec.reserve(max_accel_structs);

    for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
        VkDescriptorSetLayoutBinding dslb = {};
        dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
        dslb.descriptorCount = 1;
        dslb.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
        dslb.binding = i;
        dslb_vec.push_back(dslb);
    }

    VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
    ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
    ds_layout_ci.bindingCount = dslb_vec.size();
    ds_layout_ci.pBindings = dslb_vec.data();

    vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
    ASSERT_TRUE(ds_layout.initialized());

    VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
    pipeline_layout_ci.setLayoutCount = 1;
    pipeline_layout_ci.pSetLayouts = &ds_layout.handle();

    m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
    m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
    vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, MaxDescriptorSetAccelerationStructures) {
    TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);

    // Create one descriptor set layout holding (maxDescriptorSetAccelerationStructures + 1) bindings
    // in total for two different shader stage
    const uint32_t max_accel_structs = accel_struct_props.maxDescriptorSetAccelerationStructures;
    if (max_accel_structs > 4096) {
        GTEST_SKIP() << "maxDescriptorSetAccelerationStructures is too large";
    } else if (max_accel_structs < 1) {
        GTEST_SKIP() << "maxDescriptorSetAccelerationStructures is 1";
    }

    std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
    dslb_vec.reserve(max_accel_structs);

    for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
        VkDescriptorSetLayoutBinding dslb = {};
        dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
        dslb.descriptorCount = 1;
        dslb.stageFlags = (i % 2) ? VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR : VK_SHADER_STAGE_CALLABLE_BIT_KHR;
        dslb.binding = i;
        dslb_vec.push_back(dslb);
    }

    VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
    ds_layout_ci.bindingCount = dslb_vec.size();
    ds_layout_ci.pBindings = dslb_vec.data();

    vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
    ASSERT_TRUE(ds_layout.initialized());

    VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
    pipeline_layout_ci.setLayoutCount = 1;
    pipeline_layout_ci.pSetLayouts = &ds_layout.handle();

    m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-03573");
    // Lazy way to not query
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03571");
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
    vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, MaxDescriptorSetUpdateAfterBindAccelerationStructures) {
    TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);

    // Create one descriptor set layout with flag VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT holding
    // (maxDescriptorSetUpdateAfterBindAccelerationStructures + 1) bindings in total for two different shader stage
    const uint32_t max_accel_structs = accel_struct_props.maxDescriptorSetUpdateAfterBindAccelerationStructures;
    if (max_accel_structs > 4096) {
        GTEST_SKIP() << "maxDescriptorSetUpdateAfterBindAccelerationStructures is too large";
    } else if (max_accel_structs < 1) {
        GTEST_SKIP() << "maxDescriptorSetUpdateAfterBindAccelerationStructures is 1";
    }

    std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
    dslb_vec.reserve(max_accel_structs);

    for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
        VkDescriptorSetLayoutBinding dslb = {};
        dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
        dslb.descriptorCount = 1;
        dslb.stageFlags = (i % 2) ? VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR : VK_SHADER_STAGE_CALLABLE_BIT_KHR;
        dslb.binding = i;
        dslb_vec.push_back(dslb);
    }

    VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
    ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
    ds_layout_ci.bindingCount = dslb_vec.size();
    ds_layout_ci.pBindings = dslb_vec.data();

    vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
    ASSERT_TRUE(ds_layout.initialized());

    VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
    pipeline_layout_ci.setLayoutCount = 1;
    pipeline_layout_ci.pSetLayouts = &ds_layout.handle();

    m_errorMonitor->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
    // Lazy way to not query
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
    vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BeginQueryQueryPoolType) {
    TEST_DESCRIPTION("Test CmdBeginQuery with invalid queryPool queryType");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddOptionalExtensions(VK_NV_RAY_TRACING_EXTENSION_NAME);
    AddOptionalExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
    AddOptionalExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    RETURN_IF_SKIP(InitFramework());

    const bool khr_acceleration_structure = IsExtensionsEnabled(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    const bool nv_ray_tracing = IsExtensionsEnabled(VK_NV_RAY_TRACING_EXTENSION_NAME);
    const bool ext_transform_feedback = IsExtensionsEnabled(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
    const bool rt_maintenance_1 = IsExtensionsEnabled(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);

    if (!khr_acceleration_structure && !nv_ray_tracing) {
        GTEST_SKIP() << "Extensions " << VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME << " and " << VK_NV_RAY_TRACING_EXTENSION_NAME
                     << " are not supported.";
    }
    RETURN_IF_SKIP(InitState());

    if (khr_acceleration_structure) {
        auto cmd_begin_query = [this, ext_transform_feedback](VkQueryType query_type, auto vuid_begin_query,
                                                              auto vuid_begin_query_indexed) {
            vkt::QueryPool query_pool(*m_device, query_type, 1);

            m_command_buffer.Begin();
            m_errorMonitor->SetDesiredError(vuid_begin_query);
            vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
            m_errorMonitor->VerifyFound();

            if (ext_transform_feedback) {
                m_errorMonitor->SetDesiredError(vuid_begin_query_indexed);
                vk::CmdBeginQueryIndexedEXT(m_command_buffer, query_pool, 0, 0, 0);
                m_errorMonitor->VerifyFound();
            }
            m_command_buffer.End();
        };

        cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-04728",
                        "VUID-vkCmdBeginQueryIndexedEXT-queryType-04728");
        cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-04728",
                        "VUID-vkCmdBeginQueryIndexedEXT-queryType-04728");

        if (rt_maintenance_1) {
            cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-06741",
                            "VUID-vkCmdBeginQueryIndexedEXT-queryType-06741");
            cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
                            "VUID-vkCmdBeginQuery-queryType-06741", "VUID-vkCmdBeginQueryIndexedEXT-queryType-06741");
        }
    }
    if (nv_ray_tracing) {
        vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV, 1);

        m_command_buffer.Begin();
        m_errorMonitor->SetDesiredError("VUID-vkCmdBeginQuery-queryType-04729");
        vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
        m_errorMonitor->VerifyFound();

        if (ext_transform_feedback) {
            m_errorMonitor->SetDesiredError("VUID-vkCmdBeginQueryIndexedEXT-queryType-04729");
            vk::CmdBeginQueryIndexedEXT(m_command_buffer, query_pool, 0, 0, 0);
            m_errorMonitor->VerifyFound();
        }
        m_command_buffer.End();
    }
}

TEST_F(NegativeRayTracing, CopyUnboundAccelerationStructure) {
    TEST_DESCRIPTION("Test CmdCopyAccelerationStructureKHR with buffer not bound to memory");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas_no_mem = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas_no_mem->SetDeviceBufferInitNoMem(true);
    blas_no_mem->Create();

    auto valid_blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    valid_blas->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas_no_mem->handle();
    copy_info.dst = valid_blas->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    copy_info.src = valid_blas->handle();
    copy_info.dst = blas_no_mem->handle();
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CopyAccelerationStructureOverlappingMemory) {
    TEST_DESCRIPTION("Test CmdCopyAccelerationStructureKHR with both acceleration structures bound to the same memory");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas_1 = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    const VkAccelerationStructureBuildSizesInfoKHR size_info = blas_1.GetSizeInfo();

    VkBufferCreateInfo blas_buffer_ci = vku::InitStructHelper();
    blas_buffer_ci.size = size_info.accelerationStructureSize;
    blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                           VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
    vkt::Buffer buffer_1(*m_device, blas_buffer_ci, vkt::no_mem);
    vkt::Buffer buffer_2(*m_device, blas_buffer_ci, vkt::no_mem);

    VkMemoryRequirements mem_reqs{};
    vk::GetBufferMemoryRequirements(device(), buffer_1, &mem_reqs);

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);

    alloc_info.allocationSize = std::max(size_info.accelerationStructureSize, mem_reqs.size);
    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    buffer_1.BindMemory(buffer_memory, 0);
    buffer_2.BindMemory(buffer_memory, 0);

    blas_1.GetDstAS()->SetDeviceBuffer(std::move(buffer_1));
    m_command_buffer.Begin();
    blas_1.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_device->Wait();

    auto empty_blas_2 = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, size_info.accelerationStructureSize);
    empty_blas_2->SetDeviceBuffer(std::move(buffer_2));
    empty_blas_2->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas_1.GetDstAS()->handle();
    copy_info.dst = empty_blas_2->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-dst-07791");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdCopyUnboundAccelerationStructure) {
    TEST_DESCRIPTION("Test CmdCopyAccelerationStructureKHR with buffers not bound to memory");

    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(Init());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                      VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
    vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = buffer.MemoryRequirements();
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper(&alloc_flags);
    memory_alloc.allocationSize = memory_requirements.size;
    const bool memory_found =
        m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
                                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
    if (!memory_found) {
        GTEST_SKIP() << "Could not find suitable memory type, skipping test";
    }
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, buffer, device_memory, 0);

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas->SetDeviceBuffer(std::move(buffer));
    blas->Create();

    auto blas_no_mem = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas_no_mem->SetDeviceBufferInitNoMem(true);
    blas_no_mem->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas_no_mem->handle();
    copy_info.dst = blas->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    copy_info.src = blas->handle();
    copy_info.dst = blas_no_mem->handle();

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CopyAccelerationStructureNoHostMem) {
    TEST_DESCRIPTION("Test CmdCopyAccelerationStructureKHR with buffers not bound to memory");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_OPACITY_MICROMAP_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::deviceAddressCommands);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::micromap);
    RETURN_IF_SKIP(Init());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = buffer.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
    memory_alloc.allocationSize = memory_requirements.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, buffer, device_memory, 0);

    auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
    blas->Create();

    vkt::Buffer buffer_no_host_mem(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements_no_host = buffer_no_host_mem.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc_no_host = vku::InitStructHelper();
    memory_alloc_no_host.allocationSize = memory_requirements_no_host.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements_no_host.memoryTypeBits, &memory_alloc_no_host, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory_no_host(*m_device, memory_alloc_no_host);
    ASSERT_TRUE(device_memory_no_host.initialized());
    vk::BindBufferMemory(*m_device, buffer_no_host_mem, device_memory_no_host, 0);

    auto blas_no_host_mem = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
    blas_no_host_mem->SetDeviceBuffer(std::move(buffer_no_host_mem));
    blas_no_host_mem->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;

    copy_info.src = blas_no_host_mem->handle();
    copy_info.dst = blas->handle();

    vkt::Buffer as_buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR, vkt::device_address);

    VkDeviceAddressRangeKHR micromapAddress;
    micromapAddress.address = as_buffer.Address();
    micromapAddress.size = 4096;

    VkAccelerationStructureKHR as;
    VkAccelerationStructureCreateInfo2KHR asci = vku::InitStructHelper();
    asci.addressRange = micromapAddress;

    vk::CreateAccelerationStructure2KHR(device(), &asci, NULL, &as);

    m_errorMonitor->SetDesiredError("VUID-vkCopyAccelerationStructureKHR-buffer-03727");
    vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();

    copy_info.src = blas->handle();
    copy_info.dst = blas_no_host_mem->handle();

    m_errorMonitor->SetDesiredError("VUID-vkCopyAccelerationStructureKHR-buffer-03728");
    vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();

    vkt::Buffer as_buffer2(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR, vkt::device_address);
    VkDeviceAddressRangeKHR micromapAddress2;
    micromapAddress2.address = as_buffer2.Address();
    micromapAddress2.size = 4096;

    VkAccelerationStructureKHR as2;
    VkAccelerationStructureCreateInfo2KHR asci2 = vku::InitStructHelper();
    asci2.addressRange = micromapAddress2;
    vk::CreateAccelerationStructure2KHR(device(), &asci2, NULL, &as2);

    copy_info.src = as;
    copy_info.dst = as2;
    m_errorMonitor->SetDesiredError("VUID-vkCopyAccelerationStructureKHR-src-11588");
    m_errorMonitor->SetDesiredError("VUID-vkCopyAccelerationStructureKHR-dst-11589");
    vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();
    vk::DestroyAccelerationStructureKHR(device(), as, nullptr);
    vk::DestroyAccelerationStructureKHR(device(), as2, nullptr);
}

TEST_F(NegativeRayTracing, CmdCopyMemoryToAccelerationStructure) {
    TEST_DESCRIPTION("Validate CmdCopyMemoryToAccelerationStructureKHR with dst buffer not bound to memory");

    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_OPACITY_MICROMAP_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::deviceAddressCommands);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::micromap);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    if (IsPlatformMockICD()) {
        GTEST_SKIP() << "Test not supported by MockICD";
    }
    RETURN_IF_SKIP(InitState());

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    vkt::Buffer src_buffer(*m_device, 4096, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                           VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);

    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 1024;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer dst_buffer(*m_device, buffer_ci, vkt::no_mem);

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 0);
    blas->SetDeviceBuffer(std::move(dst_buffer));
    blas->Create();

    VkMemoryAllocateFlagsInfo alloc_flags_info = vku::InitStructHelper();
    alloc_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;

    vkt::Buffer as_buffer(*m_device, 4096,
                          VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &alloc_flags_info);

    VkDeviceAddressRangeKHR micromapAddress;
    micromapAddress.address = as_buffer.Address();
    micromapAddress.size = 4096;

    VkAccelerationStructureKHR as;
    VkAccelerationStructureCreateInfo2KHR asci = vku::InitStructHelper();
    asci.addressFlags = VK_ADDRESS_COMMAND_PROTECTED_BIT_KHR;
    asci.addressRange = micromapAddress;
    asci.type = VK_ACCELERATION_STRUCTURE_TYPE_OPACITY_MICROMAP_KHR;

    vk::CreateAccelerationStructure2KHR(device(), &asci, NULL, &as);

    VkCopyMemoryToAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src.deviceAddress = src_buffer.Address();
    copy_info.dst = blas->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;

    {
        copy_info.src.deviceAddress += 64;
        m_errorMonitor->SetDesiredError("VUID-vkCmdCopyMemoryToAccelerationStructureKHR-pInfo-03743");
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdCopyMemoryToAccelerationStructureKHR-commandBuffer-cmdpool");
        m_command_buffer.Begin();
        vk::CmdCopyMemoryToAccelerationStructureKHR(m_command_buffer, &copy_info);
        m_command_buffer.End();
        m_errorMonitor->VerifyFound();
    }

    vk::DestroyAccelerationStructureKHR(device(), as, NULL);
}

TEST_F(NegativeRayTracing, BuildAccelerationStructureKHRSrcUnbound) {
    TEST_DESCRIPTION("vkBuildAccelerationStructuresKHR with srcAccelerationStructure buffer not bound to memory");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    auto src_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    src_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    src_blas.BuildHost();

    src_blas.GetDstAS()->GetBuffer().Memory().Destroy();

    auto update_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    update_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    update_blas.SetSrcAS(src_blas.GetDstAS());
    update_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03708");
    update_blas.BuildHost();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BuildAccelerationStructureKHR) {
    TEST_DESCRIPTION("Validate buffers used in vkBuildAccelerationStructureKHR");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = non_host_visible_buffer.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
    memory_alloc.allocationSize = memory_requirements.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, non_host_visible_buffer, device_memory, 0);

    vkt::Buffer host_buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas.GetDstAS()->SetDeviceBuffer(std::move(non_host_visible_buffer));

    // .dstAccelerationStructure buffer is not bound to host visible memory
    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03722");
    blas.BuildHost();
    m_errorMonitor->VerifyFound();
}

// github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11839
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructureModeUpdate) {
    TEST_DESCRIPTION("In an acceleration structure update, source acceleration structure was not built");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(Init());

    auto host_cached_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);

    host_cached_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    host_cached_blas.SetSrcAS(vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096));
    host_cached_blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03667");
    host_cached_blas.BuildHost();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesDestroyedMemory) {
    TEST_DESCRIPTION("vkWriteAccelerationStructuresPropertiesKHR with acceleration structure buffer memory destroyed");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
    blas.BuildHost();

    blas.GetDstAS()->GetBuffer().Memory().Destroy();

    constexpr size_t stride = sizeof(VkDeviceSize);
    constexpr size_t data_size = sizeof(VkDeviceSize) * stride;
    uint8_t data[data_size];

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-buffer-03736");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data_size, data, stride);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructureMemory) {
    TEST_DESCRIPTION("Test memory in vkWriteAccelerationStructuresPropertiesKHR is host visible");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = non_host_visible_buffer.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
    memory_alloc.allocationSize = memory_requirements.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, non_host_visible_buffer, device_memory, 0);

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas.GetDstAS()->SetDeviceBuffer(std::move(non_host_visible_buffer));

    // .dstAccelerationStructure buffer is not bound to host visible memory
    m_errorMonitor->SetAllowedFailureMsg("VUID-vkBuildAccelerationStructuresKHR-pInfos-03722");
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
    blas.BuildHost();
    m_errorMonitor->VerifyFound();

    std::vector<uint32_t> data(4096);
    // .dstAccelerationStructure buffer is not bound to host visible memory
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-buffer-03733");
    vk::WriteAccelerationStructuresPropertiesKHR(device(), 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data.size(), data.data(),
                                                 data.size());
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CopyMemoryToAccelerationStructureHostAddress) {
    TEST_DESCRIPTION("vkCopyMemoryToAccelerationStructureKHR but the hostAddress is not aligned to 16.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(Init());

    auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
    blas->Create();

    VkDeviceOrHostAddressConstKHR output_data;
    output_data.hostAddress = reinterpret_cast<void*>(0x00000021);

    VkCopyMemoryToAccelerationStructureInfoKHR info = vku::InitStructHelper();
    info.dst = blas->handle();
    info.src = output_data;
    info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;

    m_errorMonitor->SetDesiredError("VUID-vkCopyMemoryToAccelerationStructureKHR-pInfo-03750");
    vk::CopyMemoryToAccelerationStructureKHR(device(), VK_NULL_HANDLE, &info);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CopyMemoryToAsBuffer) {
    TEST_DESCRIPTION("Test invalid buffer used in vkCopyMemoryToAccelerationStructureKHR.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(Init());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = non_host_visible_buffer.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
    memory_alloc.allocationSize = memory_requirements.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, non_host_visible_buffer, device_memory, 0);

    auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, buffer_ci.size);
    blas->SetDeviceBuffer(std::move(non_host_visible_buffer));
    blas->Create();

    uint8_t output[4096];
    uint8_t* aligned_output = reinterpret_cast<uint8_t*>(Align<uintptr_t>(reinterpret_cast<uintptr_t>(output), 16));
    VkDeviceOrHostAddressConstKHR output_data;
    output_data.hostAddress = aligned_output;

    VkCopyMemoryToAccelerationStructureInfoKHR info = vku::InitStructHelper();
    info.dst = blas->handle();
    info.src = output_data;
    info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;

    // .dstAccelerationStructure buffer is not bound to host visible memory
    m_errorMonitor->SetDesiredError("VUID-vkCopyMemoryToAccelerationStructureKHR-buffer-03730");
    vk::CopyMemoryToAccelerationStructureKHR(device(), VK_NULL_HANDLE, &info);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, NullCreateAccelerationStructureKHR) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureKHR as;
    m_errorMonitor->SetDesiredError("VUID-vkCreateAccelerationStructureKHR-pCreateInfo-parameter");
    vk::CreateAccelerationStructureKHR(device(), nullptr, nullptr, &as);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CreateAccelerationStructureKHR) {
    TEST_DESCRIPTION("Validate acceleration structure creation.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureKHR as;
    VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    vkt::Buffer buffer(*m_device, 4096,
                       VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
    as_create_info.buffer = buffer;
    as_create_info.createFlags = 0;
    as_create_info.offset = 0;
    as_create_info.size = 0;
    as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    as_create_info.deviceAddress = 0;

    VkBufferDeviceAddressInfo device_address_info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, NULL, buffer};
    VkDeviceAddress device_address = vk::GetBufferDeviceAddressKHR(device(), &device_address_info);
    // invalid buffer;
    {
        vkt::Buffer invalid_buffer(*m_device, 4096, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
                                   VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
        VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
        invalid_as_create_info.buffer = invalid_buffer;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-buffer-03614");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();
    }

    // invalid deviceAddress and flag;
    {
        VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
        invalid_as_create_info.deviceAddress = device_address;
        m_errorMonitor->SetDesiredError("VUID-vkCreateAccelerationStructureKHR-deviceAddress-03488");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-deviceAddress-03612");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();

        invalid_as_create_info.deviceAddress = 0;
        invalid_as_create_info.createFlags = VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-createFlags-parameter");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();
    }

    // invalid size and offset;
    {
        VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
        invalid_as_create_info.size = 4097;  // buffer size is 4096
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-offset-03616");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();
    }

    // invalid sType;
    {
        VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
        invalid_as_create_info.sType = VK_STRUCTURE_TYPE_MAX_ENUM;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-sType-sType");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();
    }

    // invalid type;
    {
        VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
        invalid_as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-type-parameter");
        vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, CreateAccelerationStructureFeature) {
    SetTargetApiVersion(VK_API_VERSION_1_1);

    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR);

    VkAccelerationStructureKHR as;
    VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
    as_create_info.buffer = buffer;
    as_create_info.size = 4096;
    as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;

    m_errorMonitor->SetDesiredError("VUID-vkCreateAccelerationStructureKHR-accelerationStructure-03611");
    vk::CreateAccelerationStructureKHR(device(), &as_create_info, nullptr, &as);
    m_errorMonitor->VerifyFound();

    m_errorMonitor->SetDesiredError("VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-08934");
    vk::DestroyAccelerationStructureKHR(device(), as, nullptr);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CreateAccelerationStructureKHRReplayFeature) {
    TEST_DESCRIPTION("Validate acceleration structure creation replay feature.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);

    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    vkt::Buffer buffer(*m_device, 4096,
                       VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);

    VkBufferDeviceAddressInfo device_address_info = vku::InitStructHelper();
    device_address_info.buffer = buffer;
    VkDeviceAddress device_address = vk::GetBufferDeviceAddressKHR(device(), &device_address_info);

    VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
    as_create_info.buffer = buffer;
    as_create_info.createFlags = VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR;
    as_create_info.offset = 0;
    as_create_info.size = 0;
    as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    as_create_info.deviceAddress = device_address;

    VkAccelerationStructureKHR as;
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoKHR-createFlags-03613");
    m_errorMonitor->SetDesiredError("VUID-vkCreateAccelerationStructureKHR-deviceAddress-03488");
    vk::CreateAccelerationStructureKHR(device(), &as_create_info, nullptr, &as);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, GetAccelerationStructureAddressBabBuffer) {
    TEST_DESCRIPTION(
        "Call vkGetAccelerationStructureDeviceAddressKHR on an acceleration structure whose buffer is missing usage "
        "VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, and whose memory has been destroyed");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas->SetBufferUsageFlags(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR);
    blas->Create();

    blas->GetBuffer().Memory().Destroy();
    m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureDeviceAddressKHR-pInfo-09541");
    m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureDeviceAddressKHR-pInfo-09542");
    (void)blas->GetAccelerationStructureDeviceAddress();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CmdTraceRaysKHR) {
    TEST_DESCRIPTION("Validate vkCmdTraceRaysKHR.");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Create ray tracing pipeline
    const vkt::PipelineLayout pipeline_layout(*m_device, {});
    VkPipeline raytracing_pipeline = VK_NULL_HANDLE;
    {
        VkShaderObj rgen_shader(*m_device, kRayTracingMinimalGlsl, VK_SHADER_STAGE_RAYGEN_BIT_KHR, SPV_ENV_VULKAN_1_2);
        VkShaderObj chit_shader(*m_device, kRayTracingMinimalGlsl, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, SPV_ENV_VULKAN_1_2);

        std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages;
        shader_stages[0] = vku::InitStructHelper();
        shader_stages[0].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
        shader_stages[0].module = chit_shader;
        shader_stages[0].pName = "main";

        shader_stages[1] = vku::InitStructHelper();
        shader_stages[1].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
        shader_stages[1].module = rgen_shader;
        shader_stages[1].pName = "main";

        std::array<VkRayTracingShaderGroupCreateInfoKHR, 1> shader_groups;
        shader_groups[0] = vku::InitStructHelper();
        shader_groups[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
        shader_groups[0].generalShader = 1;
        shader_groups[0].closestHitShader = VK_SHADER_UNUSED_KHR;
        shader_groups[0].anyHitShader = VK_SHADER_UNUSED_KHR;
        shader_groups[0].intersectionShader = VK_SHADER_UNUSED_KHR;

        VkRayTracingPipelineCreateInfoKHR raytracing_pipeline_ci = vku::InitStructHelper();
        raytracing_pipeline_ci.flags = 0;
        raytracing_pipeline_ci.stageCount = static_cast<uint32_t>(shader_stages.size());
        raytracing_pipeline_ci.pStages = shader_stages.data();
        raytracing_pipeline_ci.pGroups = shader_groups.data();
        raytracing_pipeline_ci.groupCount = shader_groups.size();
        raytracing_pipeline_ci.layout = pipeline_layout;

        const VkResult result = vk::CreateRayTracingPipelinesKHR(*m_device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1,
                                                                 &raytracing_pipeline_ci, nullptr, &raytracing_pipeline);
        ASSERT_EQ(VK_SUCCESS, result);
    }

    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.usage =
        VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR;
    buffer_ci.size = 4096;
    vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);

    VkMemoryRequirements mem_reqs;
    vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = 4096;
    vkt::DeviceMemory mem(*m_device, alloc_info);
    vk::BindBufferMemory(device(), buffer, mem, 0);

    VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_properties = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(ray_tracing_properties);

    const VkDeviceAddress device_address = buffer.Address();

    const VkStridedDeviceAddressRegionKHR stridebufregion = {device_address, ray_tracing_properties.shaderGroupHandleAlignment,
                                                             ray_tracing_properties.shaderGroupHandleAlignment};

    m_command_buffer.Begin();

    // Invalid stride multiplier
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.stride = (stridebufregion.size + 1) % stridebufregion.size;
        if (invalid_stride.stride > 0) {
            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-03694");
            vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride, 100, 100,
                                1);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-03690");
            vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion, 100, 100,
                                1);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-03686");
            vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion, 100, 100,
                                1);
            m_errorMonitor->VerifyFound();
        }
    }
    // Invalid stride, greater than maxShaderGroupStride
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        uint32_t align = ray_tracing_properties.shaderGroupHandleSize;
        invalid_stride.stride = static_cast<VkDeviceSize>(ray_tracing_properties.maxShaderGroupStride) +
                                (align - (ray_tracing_properties.maxShaderGroupStride % align));
        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-04041");
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride, 100, 100, 1);
        m_errorMonitor->VerifyFound();

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-04035");
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion, 100, 100, 1);
        m_errorMonitor->VerifyFound();

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-stride-04029");
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, raytracing_pipeline);

    // buffer is missing flag VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
    {
        buffer_ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
        vkt::Buffer buffer_missing_flag(*m_device, buffer_ci, vkt::no_mem);
        vk::BindBufferMemory(device(), buffer_missing_flag, mem, 0);
        const VkDeviceAddress device_address_missing_flag = buffer_missing_flag.Address();

        // buffer is missing flag VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
        if (device_address_missing_flag == device_address) {
            VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
            // This address is the same as the one from the first (valid) buffer, so no validation error
            invalid_stride.deviceAddress = device_address_missing_flag;
            vk::CmdTraceRaysKHR(m_command_buffer, &invalid_stride, &stridebufregion, &stridebufregion, &stridebufregion, 100, 100,
                                1);
        }
    }

    // pRayGenShaderBindingTable address range and stride are invalid
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.stride = 8128;
        invalid_stride.size = 8128;
        m_errorMonitor->SetDesiredError("VUID-VkStridedDeviceAddressRegionKHR-size-04631");
        m_errorMonitor->SetDesiredError("VUID-VkStridedDeviceAddressRegionKHR-size-04632");
        vk::CmdTraceRaysKHR(m_command_buffer, &invalid_stride, &stridebufregion, &stridebufregion, &stridebufregion, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    // pMissShaderBindingTable->deviceAddress == 0
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.deviceAddress = 0;
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }
    // pHitShaderBindingTable->deviceAddress == 0
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.deviceAddress = 0;
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion, 100, 100, 1);
    }
    // pCallableShaderBindingTable->deviceAddress == 0
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.deviceAddress = 0;
        vk::CmdTraceRaysKHR(m_command_buffer, &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride, 100, 100, 1);
    }

    m_command_buffer.End();

    vk::DestroyPipeline(device(), raytracing_pipeline, nullptr);
}

TEST_F(NegativeRayTracing, CmdTraceRaysIndirectKHR) {
    TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirectKHR.");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_properties = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(ray_tracing_properties);

    vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address);
    const VkDeviceAddress device_address = buffer.Address();

    VkStridedDeviceAddressRegionKHR stridebufregion = {};
    stridebufregion.deviceAddress = device_address;
    stridebufregion.stride = ray_tracing_properties.shaderGroupHandleAlignment;
    stridebufregion.size = stridebufregion.stride;

    m_command_buffer.Begin();
    // Invalid stride multiplier
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        invalid_stride.stride = (stridebufregion.size + 1) % stridebufregion.size;
        invalid_stride.size = invalid_stride.stride;
        if (invalid_stride.stride > 0) {
            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03694");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride,
                                        device_address);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03690");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion,
                                        device_address);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03686");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion,
                                        device_address);
            m_errorMonitor->VerifyFound();
        }
    }
    // Invalid stride, greater than maxShaderGroupStride
    // Given the invalid stride computation, stride is likely to also be misaligned, so allow above errors
    {
        VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
        if (ray_tracing_properties.maxShaderGroupStride ==
            std::numeric_limits<decltype(ray_tracing_properties.maxShaderGroupStride)>::max()) {
            printf("ray_tracing_properties.maxShaderGroupStride has maximum possible value, skipping related tests\n");
        } else {
            invalid_stride.stride = ray_tracing_properties.maxShaderGroupStride + 1;

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-04041");
            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03694");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride,
                                        device_address);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-04035");
            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03690");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion,
                                        device_address);
            m_errorMonitor->VerifyFound();

            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-04029");
            m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirectKHR-stride-03686");
            vk::CmdTraceRaysIndirectKHR(m_command_buffer, &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion,
                                        device_address);
            m_errorMonitor->VerifyFound();
        }
    }
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdTraceRaysIndirect2KHRFeatureDisabled) {
    TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirect2KHR.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);

    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address);
    const VkDeviceAddress device_address = buffer.Address();

    m_command_buffer.Begin();
    // No VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR was in the device create info pNext chain
    {
        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-rayTracingPipelineTraceRaysIndirect2-03637");
        vk::CmdTraceRaysIndirect2KHR(m_command_buffer, device_address);
        m_errorMonitor->VerifyFound();
    }
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdTraceRaysIndirect2KHRAddress) {
    TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirect2KHR.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
    const VkDeviceAddress device_address = buffer.Address();

    m_command_buffer.Begin();
    // indirectDeviceAddress is not a multiple of 4
    m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-indirectDeviceAddress-03634");
    vk::CmdTraceRaysIndirect2KHR(m_command_buffer, device_address + 1);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdTraceRaysIndirectDeviceAddressUsage) {
    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address);
    const VkDeviceAddress device_address = buffer.Address();

    vkt::rt::Pipeline pipeline(*this, m_device);
    pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);
    pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl);
    pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl);
    pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
    pipeline.CreateDescriptorSet();
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
    pipeline.GetDescriptorSet().UpdateDescriptorSets();
    pipeline.Build();

    m_command_buffer.Begin();
    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
    m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-indirectDeviceAddress-03633");
    vk::CmdTraceRaysIndirect2KHR(m_command_buffer, device_address);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdTraceRaysIndirectDeviceAddress) {
    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::rt::Pipeline pipeline(*this, m_device);
    pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);
    pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl);
    pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl);
    pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
    pipeline.CreateDescriptorSet();
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
    pipeline.GetDescriptorSet().UpdateDescriptorSets();
    pipeline.Build();

    m_command_buffer.Begin();
    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    VkDeviceAddress invalid_buffer = CastToHandle<VkDeviceAddress, uintptr_t>(0xbad00000);
    vk::CmdTraceRaysIndirect2KHR(m_command_buffer, invalid_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, AccelerationStructureVersionInfoKHR) {
    TEST_DESCRIPTION("Validate VkAccelerationStructureVersionInfoKHR.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureVersionInfoKHR valid_version = vku::InitStructHelper();
    VkAccelerationStructureCompatibilityKHR compatablity;
    uint8_t mode[] = {VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR};
    valid_version.pVersionData = mode;
    {
        VkAccelerationStructureVersionInfoKHR invalid_version = valid_version;
        invalid_version.sType = VK_STRUCTURE_TYPE_MAX_ENUM;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureVersionInfoKHR-sType-sType");
        vk::GetDeviceAccelerationStructureCompatibilityKHR(device(), &invalid_version, &compatablity);
        m_errorMonitor->VerifyFound();
    }

    {
        VkAccelerationStructureVersionInfoKHR invalid_version = valid_version;
        invalid_version.pVersionData = NULL;
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureVersionInfoKHR-pVersionData-parameter");
        vk::GetDeviceAccelerationStructureCompatibilityKHR(device(), &invalid_version, &compatablity);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, IndirectCmdBuildAccelerationStructuresKHR) {
    TEST_DESCRIPTION("Validate acceleration structure indirect builds.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Command buffer indirect build
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-dstAccelerationStructure-03800");
    blas.BuildCmdBufferIndirect(m_command_buffer);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, IndirectStridesMultiple) {
    TEST_DESCRIPTION("pIndirectStrides not a multiple of 4.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetIndirectStride(13);
    blas.SetIndirectDeviceAddress(13);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pIndirectStrides-03787");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pIndirectDeviceAddresses-03648");
    blas.BuildCmdBufferIndirect(m_command_buffer);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, HostCmdBuildAccelerationStructuresKHR) {
    TEST_DESCRIPTION("Validate acceleration structure host builds.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_OPACITY_MICROMAP_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::micromap);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    {
        // Host build
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);

        auto dummy_as = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
        dummy_as->Create();

        VkAccelerationStructureTrianglesOpacityMicromapKHR triangleMicromap = vku::InitStructHelper();
        triangleMicromap.indexType = VK_INDEX_TYPE_NONE_KHR;
        triangleMicromap.micromap = dummy_as->handle();
        blas.GetGeometries()[0].GetVkObj().geometry.triangles.pNext = &triangleMicromap;
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-11705");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-dstAccelerationStructure-03800");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, CmdBuildAccelerationStructuresKHR) {
    TEST_DESCRIPTION("Validate acceleration structure building.");
    AddOptionalExtensions(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    const bool index_type_uint8 = IsExtensionsEnabled(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);

    VkPhysicalDeviceAccelerationStructurePropertiesKHR acc_struct_properties = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(acc_struct_properties);

    // Command buffer not in recording mode
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-commandBuffer-recording");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // dstAccelerationStructure == VK_NULL_HANDLE
    {  // Command buffer build
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));

        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03800");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // Positive build tests
    {
        m_command_buffer.Begin();
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.BuildCmdBuffer(m_command_buffer);
        m_command_buffer.End();
    }

    {
        m_command_buffer.Begin();
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetupBuild(true);
        blas.VkCmdBuildAccelerationStructuresKHR(m_command_buffer, false);
        m_command_buffer.End();
    }

    m_command_buffer.Begin();

    // Invalid info count
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetInfoCount(0);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-infoCount-arraylength");
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-infoCount-arraylength");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // Invalid pInfos
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetNullInfos(true);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-parameter");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // Invalid ppBuildRangeInfos
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetNullBuildRangeInfos(true);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-ppBuildRangeInfos-parameter");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // must be called outside renderpass
    {
        InitRenderTarget();
        m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-renderpass");
        blas.BuildCmdBuffer(m_command_buffer);
        m_command_buffer.EndRenderPass();
        m_errorMonitor->VerifyFound();
    }
    // Invalid flags
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-parameter");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-parameter");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    // Invalid dst buffer
    {
        // 8192 is large enough for all known driver
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        auto buffer_ci = vkt::Buffer::CreateInfo(blas.GetSizeInfo().accelerationStructureSize,
                                                 VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR);
        vkt::Buffer invalid_buffer(*m_device, buffer_ci, vkt::no_mem);
        blas.GetDstAS()->SetDeviceBuffer(std::move(invalid_buffer));
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03707");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Invalid sType
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetInfo().sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-sType-sType");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-sType-sType");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Invalid Type
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetType(VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03654");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03654");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();

        blas.SetType(VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-parameter");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-parameter");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Total number of triangles in all geometries superior to VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxPrimitiveCount
    {
        constexpr auto primitive_count = vvl::kU32Max;
        // Check that primitive count is indeed superior to limit
        if (primitive_count > acc_struct_properties.maxPrimitiveCount) {
            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
            blas.GetGeometries()[0].SetPrimitiveCount(primitive_count);
            m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03795");
            blas.GetSizeInfo();
            m_errorMonitor->VerifyFound();
        }
    }
    // Total number of AABBs in all geometries superior to VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxPrimitiveCount
    {
        constexpr auto primitive_count = vvl::kU32Max;
        // Check that primitive count is indeed superior to limit
        if (primitive_count > acc_struct_properties.maxPrimitiveCount) {
            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
            blas.GetGeometries()[0].SetPrimitiveCount(primitive_count);
            m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03794");
            blas.GetSizeInfo();
            m_errorMonitor->VerifyFound();
        }
    }
    // Invalid stride in pGeometry.geometry.aabbs (not a multiple of 8)
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
        blas.GetGeometries()[0].SetStride(1);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03545");
        blas.GetSizeInfo(false);
        m_errorMonitor->VerifyFound();
    }
    // Invalid stride in ppGeometry.geometry.aabbs (not a multiple of 8)
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
        blas.GetGeometries()[0].SetStride(1);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03545");
        blas.GetSizeInfo(true);
        m_errorMonitor->VerifyFound();
    }
    // Invalid stride in pGeometry.geometry.aabbs (superior to UINT32_MAX)
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
        blas.GetGeometries()[0].SetStride(8ull * vvl::kU32Max);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03820");
        blas.GetSizeInfo(false);
        m_errorMonitor->VerifyFound();
    }
    // Invalid stride in ppGeometry.geometry.aabbs (superior to UINT32_MAX)
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
        blas.GetGeometries()[0].SetStride(8ull * vvl::kU32Max);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03820");
        blas.GetSizeInfo(true);
        m_errorMonitor->VerifyFound();
    }
    // Invalid vertex stride
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetGeometries()[0].SetStride(VkDeviceSize(vvl::kU32Max) + 1);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03819");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03819");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Invalid index type
    if (index_type_uint8) {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetGeometries()[0].SetTrianglesIndexType(VK_INDEX_TYPE_UINT8);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798");
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // ppGeometries and pGeometries both valid pointer
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
        std::vector<VkAccelerationStructureGeometryKHR> geometries;
        for (const auto& geometry : blas.GetGeometries()) {
            geometries.emplace_back(geometry.GetVkObj());
        }
        blas.GetInfo().pGeometries = geometries.data();  // .ppGeometries is set in .BuildCmdBuffer()
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788");
        // computed scratch buffer size will be 0 since vkGetAccelerationStructureBuildSizesKHR fails
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12261");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Buffer is missing VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR usage flag
    {
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer bad_usage_buffer(*m_device, 1024,
                                     VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                                     kHostVisibleMemProps, &alloc_flags);
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(bad_usage_buffer), 3);
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Scratch data buffer is missing VK_BUFFER_USAGE_STORAGE_BUFFER_BIT usage flag
    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        const VkDeviceSize scratch_size =
            blas.GetSizeInfo().buildScratchSize + acc_struct_properties.minAccelerationStructureScratchOffsetAlignment;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        auto bad_scratch = std::make_shared<vkt::Buffer>(*m_device, scratch_size, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                                                         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
        blas.SetScratchBuffer(std::move(bad_scratch));
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12261");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }
    // Scratch data buffer is 0
    {
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        // no VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT => scratch address will be set to 0
        auto bad_scratch = std::make_shared<vkt::Buffer>(*m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                                                         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.SetScratchBuffer(std::move(bad_scratch));
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12261");
        blas.BuildCmdBuffer(m_command_buffer);
        m_errorMonitor->VerifyFound();
    }

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, AccelerationStructuresOverlappingMemory) {
    TEST_DESCRIPTION("Validate acceleration structure building when source/destination acceleration structures overlap.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    if (IsPlatformMockICD()) {
        GTEST_SKIP()
            << "Test needs acceleration structures addresses to be related to the buffer backing them, mock ICD does not do that";
    }

    constexpr size_t build_info_count = 3;

    // To get a valid VkAccelerationStructureBuildSizesInfoKHR
    auto dummy_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    dummy_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    const VkAccelerationStructureBuildSizesInfoKHR dummy_size_info = dummy_blas.GetSizeInfo();

    VkBufferCreateInfo dst_blas_buffer_ci = vku::InitStructHelper();
    dst_blas_buffer_ci.size = dummy_size_info.accelerationStructureSize;
    dst_blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;

    // All buffers used to back source/destination acceleration structures will be bound to this memory chunk
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = dummy_size_info.accelerationStructureSize;

    {
        vkt::Buffer dummy_blas_buffer(*m_device, dst_blas_buffer_ci, vkt::no_mem);
        alloc_info.allocationSize = std::max(alloc_info.allocationSize, dummy_blas_buffer.MemoryRequirements().size);
    }

    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    // Test overlapping destination acceleration structures
    {
        std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
        std::vector<vkt::as::BuildGeometryInfoKHR> build_infos;
        for (auto& dst_blas_buffer : dst_blas_buffers) {
            dst_blas_buffer.InitNoMemory(*m_device, dst_blas_buffer_ci);
            vk::BindBufferMemory(device(), dst_blas_buffer, buffer_memory, 0);

            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
            blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffer));
            build_infos.emplace_back(std::move(blas));
        }

        // Since all the destination acceleration structures are bound to the same memory, 03702 should be triggered for each pair
        // of elements in `build_infos`
        // => due to validation code optimisations, not *all* overlaps will be detected,
        // but if there is *at least one*, it will *always+ be detected.
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
        m_command_buffer.Begin();
        vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, build_infos);
        m_command_buffer.End();
        m_errorMonitor->VerifyFound();
    }

    // Test overlapping source acceleration structure and destination acceleration structures
    {
        VkBufferCreateInfo blas_buffer_ci = vku::InitStructHelper();
        blas_buffer_ci.size = dummy_size_info.accelerationStructureSize;
        blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
        std::vector<vkt::Buffer> src_blas_buffers(build_info_count);
        std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
        std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
        for (size_t i = 0; i < build_info_count; ++i) {
            src_blas_buffers[i].InitNoMemory(*m_device, blas_buffer_ci);
            vk::BindBufferMemory(device(), src_blas_buffers[i], buffer_memory, 0);

            dst_blas_buffers[i].InitNoMemory(*m_device, blas_buffer_ci);
            vk::BindBufferMemory(device(), dst_blas_buffers[i], buffer_memory, 0);

            // 1st step: build destination acceleration struct
            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
            blas.GetDstAS()->SetDeviceBuffer(std::move(src_blas_buffers[i]));
            blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
            m_command_buffer.Begin();
            blas.BuildCmdBuffer(m_command_buffer);
            m_command_buffer.End();

            // Possible 2nd step: insert memory barrier on acceleration structure buffer
            // => no need here since 2nd build call will not be executed by the driver

            // 3rd step: set destination acceleration struct as source, create new destination acceleration struct with its
            // underlying buffer bound to the same memory as the source acceleration struct, and build using update mode to trigger
            // 03701
            blas.SetSrcAS(blas.GetDstAS());
            blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
            blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
            blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffers[i]));
            blas_vec.emplace_back(std::move(blas));
        }

        // Since all the source and destination acceleration structures are bound to the same memory, 03701 and 03702 should be
        // triggered for each pair of elements in `build_infos`, and 03668 for each element
        // => due to validation code optimisations, not *all* overlaps described by 03701 and 03702 will be detected,
        // but if there is *at least one*, it will *always+ be detected.
        // Also, the emitted errors will depend on how std::lower_bound operates given an input device address range,
        // so it is unpredicatble: use SetAllowedFailureMsg to cope
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03701");
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03668");

        m_command_buffer.Begin();
        vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, blas_vec);
        m_command_buffer.End();
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, AccelerationStructuresOverlappingMemory2) {
    TEST_DESCRIPTION("Validate acceleration structure building when scratch buffers overlap.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    constexpr size_t build_info_count = 3;

    // To get a valid VkAccelerationStructureBuildSizesInfoKHR
    auto dummy_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    const VkAccelerationStructureBuildSizesInfoKHR dummy_size_info = dummy_blas.GetSizeInfo();

    VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
    scratch_buffer_ci.size = dummy_size_info.buildScratchSize;
    scratch_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                              VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;

    // All buffers used to back scratch buffers will be bound to this memory chunk
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = std::max(dummy_size_info.accelerationStructureSize, dummy_size_info.buildScratchSize);

    {
        vkt::Buffer dummy_scratch_buffer(*m_device, scratch_buffer_ci, vkt::no_mem);
        alloc_info.allocationSize = std::max(alloc_info.allocationSize, dummy_scratch_buffer.MemoryRequirements().size);
    }

    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    // Test overlapping scratch buffers
    {
        std::vector<std::shared_ptr<vkt::Buffer>> scratch_buffers(build_info_count);
        std::vector<vkt::as::BuildGeometryInfoKHR> build_infos;

        VkDeviceAddress ref_address = 0;
        for (auto& scratch_buffer : scratch_buffers) {
            scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, scratch_buffer_ci, vkt::no_mem);
            vk::BindBufferMemory(device(), scratch_buffer->handle(), buffer_memory, 0);

            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
            blas.SetScratchBuffer(std::move(scratch_buffer));
            if (ref_address == 0) {
                ref_address = blas.GetScratchBuffer()->Address();
            } else {
                if (blas.GetScratchBuffer()->Address() != ref_address) {
                    GTEST_SKIP()
                        << "Bounding two buffers to the same memory location does not result in identical buffer device addresses";
                }
            }
            build_infos.emplace_back(std::move(blas));
        }

        // Since all the scratch buffers are bound to the same memory, 03704 will be triggered for each pair of elements in
        // `build_infos`
        // => due to validation code optimisations, not *all* overlaps will be detected,
        // but if there is *at least one*, it will *always+ be detected.
        m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704", 2);
        m_command_buffer.Begin();
        vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, build_infos);
        m_command_buffer.End();
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, AccelerationStructuresOverlappingMemory3) {
    TEST_DESCRIPTION(
        "Validate acceleration structure building when destination acceleration structures and scratch buffers overlap.");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Buffer device addresses computed by the mock ICD are not aligned to the strictest alignment possible,
    // but this test has been written with this assumption in mind to make sure scratch buffers do overlap with each other and with
    // src acceleration structures
    if (IsPlatformMockICD()) {
        GTEST_SKIP() << "Test not supported by MockICD";
    }

    constexpr size_t build_info_count = 3;

    // To get a valid VkAccelerationStructureBuildSizesInfoKHR
    auto dummy_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    const VkAccelerationStructureBuildSizesInfoKHR dummy_size_info = dummy_blas.GetSizeInfo();

    VkBufferCreateInfo dst_blas_buffer_ci = vku::InitStructHelper();
    dst_blas_buffer_ci.size = dummy_size_info.accelerationStructureSize;  // large enough for all known driver
    dst_blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
    VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
    scratch_buffer_ci.size = dummy_size_info.buildScratchSize;
    scratch_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                              VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;

    // All buffers used to back destination acceleration struct and scratch will be bound to this memory chunk
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);

    alloc_info.allocationSize = std::max(dummy_size_info.accelerationStructureSize, dummy_size_info.buildScratchSize);

    {
        vkt::Buffer dummy_blas_buffer(*m_device, dst_blas_buffer_ci, vkt::no_mem);
        vkt::Buffer dummy_scratch_buffer(*m_device, scratch_buffer_ci, vkt::no_mem);
        alloc_info.allocationSize = std::max(alloc_info.allocationSize, dummy_blas_buffer.MemoryRequirements().size);
        alloc_info.allocationSize = std::max(alloc_info.allocationSize, dummy_scratch_buffer.MemoryRequirements().size);
    }

    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    // Test overlapping destination acceleration structure and scratch buffer
    {
        std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
        std::vector<std::shared_ptr<vkt::Buffer>> scratch_buffers(build_info_count);
        std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
        for (size_t i = 0; i < build_info_count; ++i) {
            dst_blas_buffers[i].InitNoMemory(*m_device, dst_blas_buffer_ci);
            vk::BindBufferMemory(device(), dst_blas_buffers[i], buffer_memory, 0);
            scratch_buffers[i] = std::make_shared<vkt::Buffer>();
            scratch_buffers[i]->InitNoMemory(*m_device, scratch_buffer_ci);
            vk::BindBufferMemory(device(), scratch_buffers[i]->handle(), buffer_memory, 0);

            auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
            blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffers[i]));
            blas.SetScratchBuffer(std::move(scratch_buffers[i]));
            blas_vec.emplace_back(std::move(blas));
        }

        // Since all the destination acceleration structures and scratch buffers are bound to the same memory, 03702, 03703 and
        // 03704 *should* be triggered for each pair of elements in `build_infos`. 03703 *should* also be triggered for individual
        // elements.
        // => due to validation code optimisations, not *all* overlaps will be detected,
        // but if there is *at least one*, it will *always+ be detected.
        // Also, the emitted errors will depend on how std::lower_bound operates given an input device address range,
        // so it is unpredicatble: use SetAllowedFailureMsg to cope
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03703");
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
        m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704");

        m_command_buffer.Begin();
        vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, blas_vec);
        m_command_buffer.End();
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, ObjInUseCmdBuildAccelerationStructureKHR) {
    TEST_DESCRIPTION("Validate acceleration structure building tracks the objects used.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();
    m_default_queue->Submit(m_command_buffer);

    // This test used to destroy buffers used for building the acceleration structure,
    // to see if there life span was correctly tracked.
    // Following issue 6461, buffers associated to a device address are not tracked anymore, as it is impossible
    // to track the "correct" one: there is not a 1 to 1 mapping between a buffer and a device address.

    m_errorMonitor->SetDesiredError("VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02442");
    vk::DestroyAccelerationStructureKHR(*m_device, blas.GetDstAS()->handle(), nullptr);
    m_errorMonitor->VerifyFound();

    m_default_queue->Wait();
}

TEST_F(NegativeRayTracing, CmdCopyAccelerationStructureToMemoryKHR) {
    TEST_DESCRIPTION(
        "vkCmdCopyAccelerationStructureToMemoryKHR with src acceleration structure not bound to memory and invalid destination "
        "address");

    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas->SetDeviceBufferInitNoMem(true);
    blas->Create();

    VkDeviceOrHostAddressKHR output_data;
    output_data.deviceAddress = 256;
    VkCopyAccelerationStructureToMemoryInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas->handle();
    copy_info.dst = output_data;
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;

    m_command_buffer.Begin();

    // duplicate errors due to questionable spec design
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-11714");
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-11715");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    vk::CmdCopyAccelerationStructureToMemoryKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CopyAccelerationStructureToMemoryKHR) {
    TEST_DESCRIPTION("vkCopyAccelerationStructureToMemoryKHR with src acceleration structure not bound to host visible memory");

    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Init a non host visible buffer
    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
    vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);
    VkMemoryRequirements memory_requirements = buffer.MemoryRequirements();
    VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
    memory_alloc.allocationSize = memory_requirements.size;
    ASSERT_TRUE(m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_alloc, 0,
                                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    vkt::DeviceMemory device_memory(*m_device, memory_alloc);
    ASSERT_TRUE(device_memory.initialized());
    vk::BindBufferMemory(*m_device, buffer, device_memory, 0);

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas->SetDeviceBuffer(std::move(buffer));
    blas->Create();

    std::vector<uint8_t> data(4096, 0);
    VkDeviceOrHostAddressKHR output_data;
    output_data.hostAddress = reinterpret_cast<void*>(Align<uintptr_t>(reinterpret_cast<uintptr_t>(data.data()), 16));
    VkCopyAccelerationStructureToMemoryInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas->handle();
    copy_info.dst = output_data;
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-vkCopyAccelerationStructureToMemoryKHR-pInfo-03731");
    vk::CopyAccelerationStructureToMemoryKHR(*m_device, VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdCopyMemoryToAccelerationStructureKHRInvalidSrcBuffer) {
    TEST_DESCRIPTION("Validate vkCmdCopyMemoryToAccelerationStructureKHR.");

    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas->Create();

    VkCopyMemoryToAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src.deviceAddress = 256;
    copy_info.dst = blas->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkCopyMemoryToAccelerationStructureInfoKHR-dst-11716");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    vk::CmdCopyMemoryToAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, UpdateAccelerationStructureKHR) {
    TEST_DESCRIPTION("Test for updating an acceleration structure without a srcAccelerationStructure");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_command_buffer.Begin();

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    // Update acceleration structure, with .srcAccelerationStructure == VK_NULL_HANDLE
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-04630");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, BuffersAndBufferDeviceAddressesMapping) {
    TEST_DESCRIPTION(
        "Test that buffers and buffer device addresses mapping is correctly handled."
        "Bound multiple buffers to the same memory so that they have the same buffer device address."
        "Some buffers are valid for use in vkCmdBuildAccelerationStructuresKHR, others are not."
        "Using buffer device addresses obtained from invalid buffers will result in a valid call to "
        "vkCmdBuildAccelerationStructuresKHR,"
        "because for this call to be valid, at least one buffer retrieved from the buffer device addresses must be valid."
        "Valid and invalid buffers having the same address, the call is valid."
        "Removing those valid buffers should cause calls to vkCmdBuildAccelerationStructuresKHR to be invalid,"
        "as long as valid buffers are correctly removed from the internal buffer device addresses to buffers mapping.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Allocate common buffer memory
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = 4096;
    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    // Create buffers, with correct and incorrect usage
    constexpr size_t N = 3;
    std::array<std::unique_ptr<vkt::as::BuildGeometryInfoKHR>, N> blas_vec{};
    const VkBufferUsageFlags good_buffer_usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
                                                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
    const VkBufferUsageFlags bad_buffer_usage =
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;

    VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
    buffer_ci.size = 4096;
    buffer_ci.usage = good_buffer_usage;
    for (size_t i = 0; i < N; ++i) {
        if (i > 0) {
            buffer_ci.usage = bad_buffer_usage;
        }

        vkt::Buffer vbo(*m_device, buffer_ci, vkt::no_mem);
        vk::BindBufferMemory(device(), vbo, buffer_memory, 0);

        vkt::Buffer ibo(*m_device, buffer_ci, vkt::no_mem);
        vk::BindBufferMemory(device(), ibo, buffer_memory, 0);

        // Those calls to vkGetBufferDeviceAddressKHR will internally record vbo and ibo device addresses
        {
            const VkDeviceAddress vbo_address = vbo.Address();
            const VkDeviceAddress ibo_address = ibo.Address();
            if (vbo_address != ibo_address) {
                GTEST_SKIP()
                    << "Bounding two buffers to the same memory location does not result in identical buffer device addresses";
            }
        }
        blas_vec[i] = std::make_unique<vkt::as::BuildGeometryInfoKHR>(
            vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
        blas_vec[i]->GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vbo), 2);
        blas_vec[i]->GetGeometries()[0].SetTrianglesDeviceIndexBuffer(std::move(ibo));
    }

    // The first series of calls to vkCmdBuildAccelerationStructuresKHR should succeed,
    // since the first vbo and ibo do have the VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR flag.
    // After deleting the valid vbo and ibo, calls are expected to fail.

    for (size_t i = 0; i < N; ++i) {
        m_command_buffer.Begin();
        blas_vec[i]->BuildCmdBuffer(m_command_buffer);
        m_command_buffer.End();
    }

    for (size_t i = 0; i < N; ++i) {
        m_command_buffer.Begin();
        if (i > 0) {
            // for vbo
            m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
            // for ibo
            m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
        }
        blas_vec[i]->VkCmdBuildAccelerationStructuresKHR(m_command_buffer);
        if (i > 0) {
            m_errorMonitor->VerifyFound();
        }
        m_command_buffer.End();

        blas_vec[i] = nullptr;
    }
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesHost) {
    TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(Init());

    // On host query with invalid query type
    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_device->Wait();

    constexpr size_t stride = 1;
    constexpr size_t data_size = sizeof(uint32_t) * stride;
    uint8_t data[data_size];
    // Incorrect query type
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06742");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION, data_size, data,
                                                 stride);
    m_errorMonitor->VerifyFound();

    // query types not known without extension
    if (IsExtensionsEnabled(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME)) {
        // queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, but stride is not a multiple of the size of VkDeviceSize
        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06731");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, data_size, data, stride);
        m_errorMonitor->VerifyFound();

        // queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR, but stride is not a
        // multiple of the size of VkDeviceSize
        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06733");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
                                                     data_size, data, stride);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesDevice) {
    TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_device->Wait();

    m_command_buffer.Begin();
    // Incorrect query type
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryType-06742");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION,
                                                    query_pool, 0);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesAccelStructDestroyedMemory) {
    TEST_DESCRIPTION(
        "call CmdWriteAccelerationStructuresPropertiesKHR on an acceleration structure whose buffer memory has been destroyed");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 1);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_device->Wait();

    blas.GetDstAS()->GetBuffer().Memory().Destroy();

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("vkCmdWriteAccelerationStructuresPropertiesKHR-buffer-03736");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(),
                                                    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, query_pool, 0);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11839
TEST_F(NegativeRayTracing, DISABLED_WriteAccelerationStructuresPropertiesDeviceBlasNotBuilt) {
    TEST_DESCRIPTION("vkCmdWriteAccelerationStructuresPropertiesKHR with unbuilt blas");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
    blas.GetDstAS()->Create();

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 1);

    m_command_buffer.Begin();
    // blas not built
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-pAccelerationStructures-04964");
    m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-commandBuffer-cmdpool");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(),
                                                    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, query_pool, 0);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// TODO - validation needs to be added as part of GPU-AV
TEST_F(NegativeRayTracing, DISABLED_CmdWriteAccelerationStructuresPropertiesDeviceBlasNotBuilt) {
    TEST_DESCRIPTION("vkCmdWriteAccelerationStructuresPropertiesKHR with unbuilt blas");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
    blas.GetDstAS()->Create();

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 1);

    m_command_buffer.Begin();
    // blas not built
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-pAccelerationStructures-11684");
    m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-commandBuffer-cmdpool");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(),
                                                    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, query_pool, 0);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesTooManyQueries) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::Buffer buffer(*m_device, 4 * sizeof(uint64_t), VK_BUFFER_USAGE_TRANSFER_DST_BIT);

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, 1);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    m_command_buffer.Begin();
    vk::CmdResetQueryPool(m_command_buffer, query_pool, 0u, 1u);
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-query-04880");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(),
                                                    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, query_pool, 1);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesMaintenance1Host) {
    TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
    RETURN_IF_SKIP(Init());

    constexpr size_t stride = sizeof(VkDeviceSize);
    constexpr size_t data_size = sizeof(VkDeviceSize) * stride;
    uint8_t data[data_size];

    // On host query with invalid query type
    {
        vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
        blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

        m_command_buffer.Begin();
        blas.BuildCmdBuffer(m_command_buffer);
        m_command_buffer.End();

        // Incorrect query type
        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06742");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION, data_size,
                                                     data, stride);
        m_errorMonitor->VerifyFound();
    }
    // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
#if 0
    // On host query type with missing BLAS flag
    {
        vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
        // missing flag
        blas.SetFlags(0);

        m_command_buffer.Begin();
        blas.BuildCmdBuffer(m_command_buffer);
        m_command_buffer.End();

        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data_size, data,
                                                     stride);
        m_errorMonitor->VerifyFound();
    }
#endif

    // On host query type with invalid stride
    {
        vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
        blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
        blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

        m_command_buffer.Begin();
        blas.BuildCmdBuffer(m_command_buffer);
        m_command_buffer.End();

        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03448");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data_size, data, 1);
        m_errorMonitor->VerifyFound();

        m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03450");
        vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, data_size, data,
                                                     1);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesMaintenance1Device) {
    TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // On device query with invalid query type
    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_device->Wait();

    m_command_buffer.Begin();
    // Incorrect query type
    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryType-06742");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION,
                                                    query_pool, 0);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesBottomLevelPointers) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
    RETURN_IF_SKIP(Init());

    auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
    blas->Create();

    constexpr size_t stride = sizeof(VkDeviceSize);
    constexpr size_t data_size = sizeof(VkDeviceSize);
    uint8_t data[data_size];

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-pAccelerationStructures-12425");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
                                                 data_size, data, stride);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CmdWriteAccelerationStructuresPropertiesBottomLevelPointers) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();
    m_device->Wait();

    vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR, 1);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-pAccelerationStructures-12425");
    vk::CmdWriteAccelerationStructuresPropertiesKHR(m_command_buffer, 1, &blas.GetDstAS()->handle(),
                                                    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
                                                    query_pool, 0);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesDataSizeTooSmall) {
    TEST_DESCRIPTION(
        "Call vkWriteAccelerationStructuresPropertiesKHR with a dataSize that is smaller that VkDeviceSize for relevant query "
        "types");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // On host query with invalid query type
    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
    blas.GetDstAS()->Create();

    constexpr size_t stride = 1;
    constexpr size_t data_size = sizeof(VkDeviceSize) * stride;
    uint8_t data[data_size];

    blas.BuildHost();

    // Incorrect data size

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03448");
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03449");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, 1, data, stride);
    m_errorMonitor->VerifyFound();

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03450");
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03451");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, 1, data, stride);
    m_errorMonitor->VerifyFound();

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06731");
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06732");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, 1, data, stride);
    m_errorMonitor->VerifyFound();

    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06733");
    m_errorMonitor->SetDesiredError("VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06734");
    vk::WriteAccelerationStructuresPropertiesKHR(*m_device, 1, &blas.GetDstAS()->handle(),
                                                 VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR, 1,
                                                 data, stride);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BuildAccelerationStructuresDeferredOperation) {
    TEST_DESCRIPTION("Call vkBuildAccelerationStructuresKHR with an invalid VkDeferredOperationKHR object");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-deferredOperation-parameter");
    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetDeferredOp(CastFromUint64<VkDeferredOperationKHR>(0xdeadbeef));
    blas.BuildHost();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidMode) {
    TEST_DESCRIPTION("Build an acceleration structure with an invalid mode");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetMode(static_cast<VkBuildAccelerationStructureModeKHR>(42));
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-mode-04628");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryType) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list changing geometry type");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to geometry type
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    const VkGeometryFlagsKHR geometry_flags = blas.GetGeometries()[0].GetFlags();
    blas.GetGeometries()[0] = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device);
    blas.GetGeometries()[0].SetFlags(geometry_flags);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03761");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryFlags) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different "
        "geometry flag");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to geometry flags
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetFlags((VkGeometryFlagsKHR)0);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03762");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesFormat) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different "
        "vertex format for the triangles");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    const VkFormat second_triangles_vertex_format = VK_FORMAT_R16G16B16_SFLOAT;

    // Invalid update to triangles vertex format
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    m_command_buffer.End();
    m_device->Wait();
    m_command_buffer.Begin();

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetScratchBuffer(std::make_shared<vkt::Buffer>());
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetTrianglesVertexFormat(second_triangles_vertex_format);

    if (!BufferFormatAndFeaturesSupported(Gpu(), second_triangles_vertex_format,
                                          VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)) {
        m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797");
    }
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03763");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesFormatMissingFeature) {
    TEST_DESCRIPTION("Use a triangles vertex format that misses the acceleration structure vertex buffer format feature");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    for (uint32_t i = 0; i < 185; ++i) {
        const VkFormat f = VkFormat(i);
        if (BufferFormatAndFeaturesSupported(Gpu(), f, VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)) {
            printf("Format %s\n", string_VkFormat(f));
        }
    }

    const VkFormat triangles_vertex_format = VK_FORMAT_R32_UINT;
    if (BufferFormatAndFeaturesSupported(Gpu(), triangles_vertex_format,
                                         VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)) {
        GTEST_SKIP()
            << "Hard coded vertex format has VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR, skipping test.";
    }

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesVertexFormat(triangles_vertex_format);

    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesMisalignedVertexStride) {
    TEST_DESCRIPTION(
        "Use a triangles vertex buffer stride that is not a multiple of the size in bytes of the smallest component of triangles "
        "vertex format");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetStride(1);

    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03735");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesMisalignedVertexBufferAddress) {
    TEST_DESCRIPTION(
        "Use a triangles vertex buffer address that is not a multiple of the size in bytes of the smallest component of triangles "
        "vertex format");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesVertexBufferDeviceAddress(1);

    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");  // device address does not belong to a buffer
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03711");  // misaligned device address
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesMaxVertex) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different "
        "maxVertex for triangles");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to triangles max vertex
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetTrianglesMaxVertex(666);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03764");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, InvalidMaxVertex) {
    TEST_DESCRIPTION("Build a BLAS made out of triangles, without using indices, and using an invalid maxVertex");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to triangles max vertex
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    blas.GetGeometries()[0].SetTrianglesIndexType(VK_INDEX_TYPE_NONE_KHR);
    blas.GetGeometries()[0].SetTrianglesMaxVertex(1);

    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-None-10775");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesIndexType) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different index "
        "type for the triangles");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to triangles index type
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetTrianglesIndexType(VkIndexType::VK_INDEX_TYPE_UINT16);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03765");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesTransformData) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different "
        "pointer for the transform data");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to triangles transform data
    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    blas.GetGeometries()[0].SetTrianglesTransformatData(0);
    blas.BuildCmdBuffer(m_command_buffer);

    m_command_buffer.End();
    m_device->Wait();
    m_command_buffer.Begin();

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetScratchBuffer(std::make_shared<vkt::Buffer>());
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetTrianglesTransformatData(666 * 16);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03766");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesVertexBufferNull) {
    TEST_DESCRIPTION(
        "Use a triangles vertex buffer specified referencing a null device address for an acceleration structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesVertexBufferDeviceAddress(0);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03804");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesIndexBufferNull) {
    TEST_DESCRIPTION(
        "Use a triangles vertex buffer specified referencing a null device address for an acceleration structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesIndexBufferDeviceAddress(0);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03806");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TrianglesIndexBufferInvalidAddress) {
    TEST_DESCRIPTION("Use a triangles vertex buffer specified referencing a device address that is referencing no existing buffer");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesIndexBufferDeviceAddress(32);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, AabbBufferInvalidAddress) {
    TEST_DESCRIPTION("Use a AABB buffer specified referencing a device address that referencing no existing buffer");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0] = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device);
    blas.GetGeometries()[0].SetAABBsDeviceAddress(32);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_BuildAccelerationStructuresInvalidUpdatesToGeometry) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with triangles "
        "transform data going from non NULL to NULL");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    // Invalid update to triangles transform data
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    vkt::Buffer transform_buffer(*m_device, 4096,
                                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    blas.GetGeometries()[0].SetTrianglesTransformatData(transform_buffer.Address());

    blas.BuildCmdBuffer(m_command_buffer);

    blas.SetSrcAS(blas.GetDstAS());
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
    blas.GetGeometries()[0].SetTrianglesTransformatData(0);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03767");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, BuildNullGeometries) {
    TEST_DESCRIPTION("Have a geometryCount > 0 but both pGeometries and ppGeometries be NULL");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    m_command_buffer.Begin();
    // Build Bottom Level Acceleration Structure
    auto blas =
        std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
    blas->SetNullGeometries(true);
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788");
    blas->GetSizeInfo();
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TransformBufferInvalidDeviceAddress) {
    TEST_DESCRIPTION(
        "Use a transform buffer specified with a device address that does not belong to an existing buffer for an acceleration "
        "structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesTransformatData(16);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TransformBufferInvalid) {
    TEST_DESCRIPTION("Use a transform buffer whose memory has been freed for an acceleration structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    vkt::Buffer transform_buffer(*m_device, 4096,
                                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesTransformatData(transform_buffer.Address());

    m_command_buffer.Begin();
    blas.SetupBuild(*m_device, true);
    transform_buffer.Memory().Destroy();
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    blas.VkCmdBuildAccelerationStructuresKHR(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, BuildAccelerationStructureMode) {
    TEST_DESCRIPTION("Use invalid mode for vkBuildAccelerationStructureKHR");
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(Init());

    vkt::Buffer host_buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas.SetMode(static_cast<VkBuildAccelerationStructureModeKHR>(0xbadbeef0));

    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-mode-04628");
    blas.BuildHost();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, InstanceBufferBadAddress) {
    TEST_DESCRIPTION("Use an invalid address for an instance buffer.");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS());

    m_command_buffer.Begin();
    tlas.SetupBuild(*m_device, true);

    tlas.GetGeometries()[0].SetInstancesDeviceAddress(0);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03813");
    tlas.VkCmdBuildAccelerationStructuresKHR(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, InstanceBufferBadMemory) {
    TEST_DESCRIPTION("Use an instance buffer whose memory has been destroyed for an acceleration structure build operation.");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS());

    m_command_buffer.Begin();
    tlas.SetupBuild(*m_device, true);

    tlas.GetGeometries()[0].GetInstance().buffer.Memory().Destroy();

    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    tlas.VkCmdBuildAccelerationStructuresKHR(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, DynamicRayTracingPipelineStack) {
    TEST_DESCRIPTION(
        "Setup a ray tracing pipeline and acceleration structure with a dynamic ray tracing stack size, "
        "but do not set size before tracing rays");
    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    if (IsPlatformMockICD()) {
        GTEST_SKIP() << "Test not supported by MockICD, will fail alignment sometimes";
    }
    RETURN_IF_SKIP(InitState());

    vkt::rt::Pipeline pipeline(*this, m_device);
    pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);
    pipeline.AddDynamicState(VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR);
    pipeline.Build();

    m_command_buffer.Begin();
    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
    m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-09458");
    vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt();
    vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt,
                        &trace_rays_sbt.callable_sbt, 1, 1, 1);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_UpdatedFirstPrimitiveCount) {
    TEST_DESCRIPTION(
        "Build a list of destination acceleration structures, then do an update build on that same list but with a different "
        "VkAccelerationStructureBuildRangeInfoKHR::primitiveCount");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);

    blas.BuildCmdBuffer(m_command_buffer);

    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    m_command_buffer.Begin();

    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetSrcAS(blas.GetDstAS());

    // Create custom build ranges, with the default valid as a template, then somehow supply it?
    auto build_range_infos = blas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].primitiveCount = 0;
    blas.SetBuildRanges(build_range_infos);

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-primitiveCount-03769");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, ScratchBufferBadAddressSpaceOpBuild) {
    TEST_DESCRIPTION("Use a scratch buffer that is too small for an acceleration structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    auto size_info = blas.GetSizeInfo(*m_device);
    if (size_info.buildScratchSize <= 64) {
        GTEST_SKIP() << "Need a big scratch size, skipping test.";
    }

    // Allocate buffer memory separately so that it can be large enough. Scratch buffer size will be smaller.
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = 4096;
    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    VkBufferCreateInfo small_buffer_ci = vku::InitStructHelper();
    small_buffer_ci.size = 64;
    small_buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;

    auto scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, small_buffer_ci, vkt::no_mem);
    scratch_buffer->BindMemory(buffer_memory, 0);

    m_command_buffer.Begin();
    blas.SetScratchBuffer(scratch_buffer);
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12258");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, ScratchBufferBadAddressSpaceOpUpdate) {
    TEST_DESCRIPTION("Use a scratch buffer that is too small for an acceleration structure update operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
    auto size_info = blas.GetSizeInfo();
    if (size_info.updateScratchSize <= 64) {
        GTEST_SKIP() << "Update scratch size too small, skipping test.";
    }

    // Allocate buffer memory separately so that it can be large enough. Scratch buffer size will be smaller.
    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;

    auto scratch_buffer =
        std::make_shared<vkt::Buffer>(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                                      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    m_command_buffer.Begin();
    blas.SetScratchBuffer(scratch_buffer);
    blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
    blas.SetSrcAS(blas.GetDstAS());
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12259");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, ScratchBufferBadMemory) {
    TEST_DESCRIPTION("Use a scratch buffer whose memory has been destroyed for an acceleration structure build operation");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());
    if (IsPlatformMockICD()) {
        GTEST_SKIP() << "Test not supported by MockICD";
    }

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
    scratch_buffer_ci.size = blas.GetSizeInfo().buildScratchSize;
    scratch_buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;

    auto scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, scratch_buffer_ci, vkt::no_mem);

    VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
    alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
    VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
    alloc_info.allocationSize = scratch_buffer->MemoryRequirements().size;
    vkt::DeviceMemory buffer_memory(*m_device, alloc_info);

    scratch_buffer->BindMemory(buffer_memory, 0);

    m_command_buffer.Begin();
    blas.SetScratchBuffer(scratch_buffer);
    blas.SetupBuild(*m_device, true);

    buffer_memory.Destroy();

    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    blas.VkCmdBuildAccelerationStructuresKHR(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, DstAsTooSmall) {
    TEST_DESCRIPTION("Try to perform a build on an acceleration structure that was created too small.");

    SetTargetApiVersion(VK_API_VERSION_1_1);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    m_command_buffer.Begin();
    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.SetUpdateDstAccelStructSizeBeforeBuild(false);

    blas.GetDstAS()->SetSize(1);
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-10126");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, TooManyInstances) {
    TEST_DESCRIPTION(
        "Call vkGetAccelerationStructureBuildSizesKHR with pMaxPrimitiveCounts[0] > "
        "VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxInstanceCount");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS());
    tlas.GetGeometries()[0].SetPrimitiveCount(vvl::kU32Max);
    m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureBuildSizesKHR-pBuildInfo-03785");
    tlas.GetSizeInfo();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, HostInstanceInvalid) {
    TEST_DESCRIPTION("build a TLAS with an invalid geometry.instances.data.hostAddress");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    // Build Bottom Level Acceleration Structure
    auto blas =
        std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device));
    blas->BuildHost();

    // Build Top Level Acceleration Structure
    vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostTopLevel(*m_device, blas);
    tlas.GetGeometries()[0].SetInstanceHostAccelStructRef(VK_NULL_HANDLE, 0);
    tlas.GetGeometries()[0].AddInstanceHostAccelStructRef(VK_NULL_HANDLE);
    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03779");
    m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03779");
    tlas.BuildHost();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, HostAccelerationStructureBuildNullPointers) {
    TEST_DESCRIPTION("Test host side accelerationStructureReference");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(Init());

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.SetEnableScratchBuild(false);
        blas.SetHostScratchBuffer(nullptr);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-12244");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
        blas.SetEnableScratchBuild(false);
        blas.SetHostScratchBuffer(nullptr);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-04630");  // Null src accel struct
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-12245");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.GetGeometries()[0].SetTrianglesHostVertexBuffer(nullptr, 1);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03771");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.GetGeometries()[0].SetTrianglesHostIndexBuffer(nullptr);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03772");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
        blas.GetGeometries()[0].SetAABBsHostBuffer(nullptr);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03774");
        blas.BuildHost();
        m_errorMonitor->VerifyFound();
    }

    {
        auto blas = std::make_shared<vkt::as::BuildGeometryInfoKHR>(
            vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device));
        blas->BuildHost();

        vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostTopLevel(*m_device, blas);
        tlas.GetGeometries()[0].SetInstanceHostAddress(nullptr);
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-pInfos-03778");
        tlas.BuildHost();
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, HostBuildOverlappingScratchBuffers) {
    TEST_DESCRIPTION("Attempt an host acceleration structure build with overlapping scratch buffers");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(Init());

    constexpr size_t blas_count = 3;

    std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
    auto scratch_data = std::make_shared<std::vector<uint8_t>>(1u << 15u, uint8_t(0));
    for (size_t i = 0; i < blas_count; ++i) {
        auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
        blas.SetHostScratchBuffer(scratch_data);
        blas.SetEnableScratchBuild(false);
        blas_vec.emplace_back(std::move(blas));
    }

    for (size_t i = 0; i < binom<size_t>(blas_count, 2); ++i) {
        m_errorMonitor->SetDesiredError("VUID-vkBuildAccelerationStructuresKHR-scratchData-03704");
    }
    vkt::as::BuildHostAccelerationStructuresKHR(*m_device, blas_vec);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, AccelerationStructureGeometry) {
    TEST_DESCRIPTION("Test VkAccelerationStructureGeometryKHR parameters");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);

    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureBuildGeometryInfoKHR build_info = vku::InitStructHelper();
    build_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    build_info.flags =
        VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;
    uint32_t max_primitives_count = 0u;
    VkAccelerationStructureBuildSizesInfoKHR build_sizes_info = vku::InitStructHelper();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-03796");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              &max_primitives_count, &build_sizes_info);
    m_errorMonitor->VerifyFound();

    build_info.flags = 0u;
    build_info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03790");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              &max_primitives_count, &build_sizes_info);
    m_errorMonitor->VerifyFound();

    VkAccelerationStructureGeometryKHR geometry = vku::InitStructHelper();
    geometry.geometry.triangles = vku::InitStructHelper();

    build_info.geometryCount = 1u;
    build_info.pGeometries = &geometry;
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03789");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              &max_primitives_count, &build_sizes_info);
    m_errorMonitor->VerifyFound();

    geometry.geometry.instances = vku::InitStructHelper();
    geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
    build_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03791");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              &max_primitives_count, &build_sizes_info);
    m_errorMonitor->VerifyFound();

    VkAccelerationStructureGeometryKHR geometries[2];
    geometries[0] = vku::InitStructHelper();
    geometries[0].geometry.triangles = vku::InitStructHelper();
    geometries[0].geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
    geometries[1] = vku::InitStructHelper();
    geometries[1].geometry.aabbs = vku::InitStructHelper();
    geometries[1].geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
    build_info.geometryCount = 2u;
    build_info.pGeometries = geometries;
    uint32_t max_primitives_counts[2] = {0u, 0u};
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03792");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              max_primitives_counts, &build_sizes_info);
    m_errorMonitor->VerifyFound();

    build_info.geometryCount = 1u;
    build_info.pGeometries = &geometry;
    geometry.geometryType = VK_GEOMETRY_TYPE_MAX_ENUM_KHR;  // Invalid
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureGeometryKHR-geometryType-parameter");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              &max_primitives_count, &build_sizes_info);
    m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12635
TEST_F(NegativeRayTracing, DISABLED_CopyAccelerationStructureMode) {
    TEST_DESCRIPTION("Test VkAccelerationStructureGeometryKHR parameters");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);

    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas1 = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
    blas1.BuildHost();

    auto blas2 = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
    blas2->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;
    copy_info.src = blas1.GetDstAS()->handle();
    copy_info.dst = blas2->handle();

    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-mode-03410");
    vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();

    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR;
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-src-03411");
    vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, StridedDeviceAddressRegion) {
    TEST_DESCRIPTION("Invalid ray gen SBT address");

    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::rt::Pipeline rt_pipeline(*this, m_device);

    rt_pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);

    rt_pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl);
    rt_pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl);

    rt_pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
    rt_pipeline.CreateDescriptorSet();
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    rt_pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
    rt_pipeline.GetDescriptorSet().UpdateDescriptorSets();

    rt_pipeline.Build();

    vkt::rt::TraceRaysSbt sbt = rt_pipeline.GetTraceRaysSbt();

    m_command_buffer.Begin();

    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rt_pipeline);

    m_errorMonitor->SetDesiredError("UNASSIGNED-TraceRays-InvalidRayGenSBTAddress");
    sbt.ray_gen_sbt.deviceAddress = 0;
    vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, InvalidAsCopy) {
    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    m_command_buffer.Begin();

    blas.BuildCmdBuffer(m_command_buffer);

    m_command_buffer.End();
    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    vkt::Buffer serialized_accel_struct_buffer(
        *m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
        vkt::device_address);

    VkCopyAccelerationStructureToMemoryInfoKHR copy_accel_struct_to_memory_info = vku::InitStructHelper();
    copy_accel_struct_to_memory_info.src = blas.GetDstAS()->handle();
    copy_accel_struct_to_memory_info.dst.deviceAddress = Align<VkDeviceAddress>(serialized_accel_struct_buffer.Address(), 256u);
    copy_accel_struct_to_memory_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-03412");
    vk::CmdCopyAccelerationStructureToMemoryKHR(m_command_buffer, &copy_accel_struct_to_memory_info);
    m_errorMonitor->VerifyFound();

    copy_accel_struct_to_memory_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;
    copy_accel_struct_to_memory_info.dst.deviceAddress += 128;
    m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureToMemoryKHR-pInfo-03740");
    vk::CmdCopyAccelerationStructureToMemoryKHR(m_command_buffer, &copy_accel_struct_to_memory_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdTraceRays) {
    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::rt::Pipeline rt_pipeline(*this, m_device);

    rt_pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);

    rt_pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl);
    rt_pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl);

    rt_pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
    rt_pipeline.CreateDescriptorSet();
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    rt_pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
    rt_pipeline.GetDescriptorSet().UpdateDescriptorSets();

    rt_pipeline.Build();

    VkPhysicalDeviceRayTracingPipelinePropertiesKHR rt_pipeline_props = vku::InitStructHelper();
    VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&rt_pipeline_props);
    vk::GetPhysicalDeviceProperties2(gpu_, &props2);

    const uint32_t handle_size_base_aligned =
        Align(rt_pipeline_props.shaderGroupHandleSize, rt_pipeline_props.shaderGroupBaseAlignment);
    const uint32_t handle_size_aligned =
        Align(rt_pipeline_props.shaderGroupHandleSize, rt_pipeline_props.shaderGroupHandleAlignment);

    const auto sbt = rt_pipeline.GetTraceRaysSbt();

    m_command_buffer.Begin();

    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rt_pipeline);

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_closest_hit_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment);
        invalid_closest_hit_sbt.deviceAddress = invalid_buffer_address;
        invalid_closest_hit_sbt.stride = handle_size_aligned;
        invalid_closest_hit_sbt.size = handle_size_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-pHitShaderBindingTable-03688");
        vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &invalid_closest_hit_sbt, &sbt.callable_sbt, 100,
                            100, 1);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_base_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_ray_gen_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment);
        invalid_ray_gen_sbt.deviceAddress = invalid_buffer_address;
        invalid_ray_gen_sbt.stride = handle_size_base_aligned;
        invalid_ray_gen_sbt.size = handle_size_base_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-pRayGenShaderBindingTable-03681");
        vk::CmdTraceRaysKHR(m_command_buffer, &invalid_ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_miss_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment);
        invalid_miss_sbt.deviceAddress = invalid_buffer_address;
        invalid_miss_sbt.stride = handle_size_aligned;
        invalid_miss_sbt.size = handle_size_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-pMissShaderBindingTable-03684");
        vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &invalid_miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_callable_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment);
        invalid_callable_sbt.deviceAddress = invalid_buffer_address;
        invalid_callable_sbt.stride = handle_size_aligned;
        invalid_callable_sbt.size = handle_size_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-pCallableShaderBindingTable-03692");
        vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &invalid_callable_sbt, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
                                VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_callable_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment) + 1;
        invalid_callable_sbt.deviceAddress = invalid_buffer_address;
        invalid_callable_sbt.stride = handle_size_aligned;
        invalid_callable_sbt.size = handle_size_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-pCallableShaderBindingTable-03693");
        vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &invalid_callable_sbt, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo sbt_buffer_info = vku::InitStructHelper();
        sbt_buffer_info.size = handle_size_base_aligned;
        sbt_buffer_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
        alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
        vkt::Buffer invalid_buffer(*m_device, sbt_buffer_info, kHostVisibleMemProps, &alloc_flags);

        VkDeviceAddress invalid_buffer_address = invalid_buffer.Address();

        VkStridedDeviceAddressRegionKHR invalid_ray_gen_sbt{};
        invalid_buffer_address = Align<VkDeviceAddress>(invalid_buffer_address, rt_pipeline_props.shaderGroupBaseAlignment);
        invalid_ray_gen_sbt.deviceAddress = invalid_buffer_address;
        invalid_ray_gen_sbt.stride = handle_size_base_aligned / 2u;
        invalid_ray_gen_sbt.size = handle_size_base_aligned;

        m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-size-04023");
        vk::CmdTraceRaysKHR(m_command_buffer, &invalid_ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
        m_errorMonitor->VerifyFound();
    }

    vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);

    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);

    m_device->Wait();
}

TEST_F(NegativeRayTracing, GetAccelerationStructureBuildSizesNullMaxPrimitiveCount) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);

    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureGeometryKHR geometry = vku::InitStructHelper();
    geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
    geometry.geometry.triangles = vku::InitStructHelper();
    geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    geometry.geometry.triangles.vertexStride = sizeof(float) * 3u;
    geometry.geometry.triangles.maxVertex = 3u;
    geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR;
    geometry.geometry.triangles.indexData.deviceAddress = 0;
    geometry.geometry.triangles.transformData.deviceAddress = 0;
    geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;

    VkAccelerationStructureBuildGeometryInfoKHR build_info = vku::InitStructHelper();
    build_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    build_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
    build_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
    build_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
    build_info.srcAccelerationStructure = VK_NULL_HANDLE;
    build_info.dstAccelerationStructure = VK_NULL_HANDLE;
    build_info.geometryCount = 1;
    build_info.pGeometries = &geometry;
    build_info.ppGeometries = NULL;
    build_info.scratchData.deviceAddress = 0;
    VkAccelerationStructureBuildSizesInfoKHR build_sizes_info = vku::InitStructHelper();
    m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureBuildSizesKHR-pMaxPrimitiveCounts-11612");
    vk::GetAccelerationStructureBuildSizesKHR(device(), VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR, &build_info,
                                              nullptr, &build_sizes_info);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, BuildPartitionedAccelerationStructureInfo) {
    TEST_DESCRIPTION("Validate all the valid usages of VkBuildPartitionedAccelerationStructureInfo");

    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::partitionedAccelerationStructure);
    AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());
    // MockICD will cause the test to fail, skip it
    if (IsPlatformMockICD()) {
        GTEST_SKIP() << "Test not supported by MockICD";
    }

    int instance_count = 20;
    int partition_count = 5;

    VkPartitionedAccelerationStructureInstancesInputNV input_info = vku::InitStructHelper();
    input_info.instanceCount = instance_count;
    input_info.maxInstancePerPartitionCount = instance_count / partition_count;
    input_info.partitionCount = partition_count;
    input_info.maxInstanceInGlobalPartitionCount = instance_count / partition_count;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;

    VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
    vk::GetPartitionedAccelerationStructuresBuildSizesNV(m_device->handle(), &input_info, &size_info);
    // memory dstAccelerationStructureData must be equal or larger than the
    // VkAccelerationStructureBuildSizesInfoKHR::accelerationStructureSize minus 1500 to cause memeory difference
    vkt::Buffer build_buffer(
        *m_device, size_info.accelerationStructureSize - 1500,
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    VkDeviceAddress ptlas_buffer_address = build_buffer.Address();

    vkt::Buffer correct_build_buffer(*m_device, size_info.accelerationStructureSize,
                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                         VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                         VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                                     vkt::device_address);
    VkDeviceAddress correct_ptlas_buffer_address = correct_build_buffer.Address();
    vkt::Buffer count_buffer(*m_device, sizeof(uint32_t),
                             VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                             vkt::device_address);

    int input = instance_count;
    auto* data = static_cast<uint32_t*>(count_buffer.Memory().Map());
    memcpy(data, &input, sizeof(input));
    VkDeviceAddress count_buffer_address = count_buffer.Address();

    // Create correct Buffer for scratchData
    vkt::Buffer scratch_buffer(*m_device, size_info.buildScratchSize,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                   VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);
    VkDeviceAddress scratch_buffer_address = scratch_buffer.Address();

    // VkAccelerationStructureBuildSizesInfoKHR::accelerationStructureSize minus 1500 to cause memeory difference
    vkt::Buffer wrong_scratch_buffer(
        *m_device, size_info.buildScratchSize - 1500,
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, vkt::device_address);
    VkDeviceAddress wrong_scratch_buffer_address = wrong_scratch_buffer.Address();

    VkBuildPartitionedAccelerationStructureInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.srcAccelerationStructureData = 0;
    command_info.dstAccelerationStructureData = 0;
    command_info.scratchData = scratch_buffer_address;
    command_info.srcInfos = 0;
    command_info.srcInfosCount = count_buffer_address;

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-dstAccelerationStructureData-parameter");
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-srcInfos-parameter");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstAccelerationStructureData = ptlas_buffer_address;
    command_info.srcInfos = count_buffer_address;  // Use a valid address going forward
    m_command_buffer.End();

    // add 1 to cause aligned error
    command_info.srcInfosCount = count_buffer_address + 1;
    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-srcInfosCount-10563");
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-dstAccelerationStructureData-10562");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10552");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10543");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    command_info.srcInfosCount = count_buffer_address;
    command_info.dstAccelerationStructureData = correct_ptlas_buffer_address;
    command_info.scratchData = 0;
    m_command_buffer.Begin();
    // scratchData must not be NULL
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-scratchData-10558");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    command_info.scratchData = wrong_scratch_buffer_address;
    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-scratchData-10559");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10550");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10541");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    command_info.scratchData = scratch_buffer_address + 1;
    command_info.dstAccelerationStructureData = correct_ptlas_buffer_address + 1;
    command_info.srcAccelerationStructureData = correct_ptlas_buffer_address + 1;
    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10542");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10544");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10545");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    command_info.scratchData = scratch_buffer_address;
    command_info.dstAccelerationStructureData = scratch_buffer_address;
    command_info.srcAccelerationStructureData = scratch_buffer_address;
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10548");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10547");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    // Test src vs dst overlap when they are different addresses (in-place update src==dst is allowed)
    // Use 256-byte aligned offset so alignment checks pass, but still within same buffer (overlapping)
    command_info.scratchData = scratch_buffer_address;
    command_info.dstAccelerationStructureData = correct_ptlas_buffer_address;
    command_info.srcAccelerationStructureData = correct_ptlas_buffer_address + 256;  // Different but overlapping (same buffer)
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildPartitionedAccelerationStructuresNV-pBuildInfo-10549");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, BuildPartitionedAccelerationStrutureInfoBadMemory) {
    TEST_DESCRIPTION(
        "Validate all buffer is a non-sparse buffer then it must be bound completely and contiguously to a single VkDeviceMemory "
        "object");

    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::partitionedAccelerationStructure);
    AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t instance_count = 20;
    uint32_t partition_count = 5;

    VkPartitionedAccelerationStructureFlagsNV ptlas_flags = vku::InitStructHelper();
    ptlas_flags.enablePartitionTranslation = true;
    VkPartitionedAccelerationStructureInstancesInputNV input_info = vku::InitStructHelper(&ptlas_flags);
    input_info.instanceCount = instance_count;
    input_info.maxInstancePerPartitionCount = instance_count / partition_count;
    input_info.partitionCount = partition_count;
    input_info.maxInstanceInGlobalPartitionCount = instance_count / partition_count;

    VkAccelerationStructureBuildSizesInfoKHR ptlas_size_info = vku::InitStructHelper();
    vk::GetPartitionedAccelerationStructuresBuildSizesNV(*m_device, &input_info, &ptlas_size_info);

    vkt::Buffer build_buffer(*m_device, ptlas_size_info.accelerationStructureSize,
                             VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                             vkt::device_address);
    VkDeviceAddress ptlas_buffer_address = build_buffer.Address();

    vkt::Buffer dst_build_buffer(*m_device, ptlas_size_info.accelerationStructureSize,
                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                                 vkt::device_address);
    VkDeviceAddress dst_ptlas_buffer_address = dst_build_buffer.Address();

    vkt::Buffer scratch_buffer(*m_device, ptlas_size_info.buildScratchSize,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                   VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);
    VkDeviceAddress scratch_buffer_address = scratch_buffer.Address();

    vkt::Buffer write_partition_buffer(
        *m_device, partition_count * sizeof(VkPartitionedAccelerationStructureWritePartitionTranslationDataNV),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, vkt::device_address);
    std::vector<VkPartitionedAccelerationStructureWritePartitionTranslationDataNV> writePartitionArgs;
    static uint32_t partitionArray[5] = {3, 0xFFFFFFFF, 0, 2, 1};
    static float partitionTranslationY[] = {0, 20, 40, 20, 0};
    for (uint32_t t = 0; t < partition_count; t++) {
        VkPartitionedAccelerationStructureWritePartitionTranslationDataNV writePartition{};
        writePartition.partitionIndex = partitionArray[t];
        writePartition.partitionTranslation[0] = 0;
        writePartition.partitionTranslation[1] = partitionTranslationY[t];
        writePartition.partitionTranslation[2] = 0;
        writePartitionArgs.push_back(writePartition);
    }

    auto* write_partition_data =
        static_cast<VkPartitionedAccelerationStructureWritePartitionTranslationDataNV*>(write_partition_buffer.Memory().Map());
    memcpy(write_partition_data, writePartitionArgs.data(),
           partition_count * sizeof(VkPartitionedAccelerationStructureWritePartitionTranslationDataNV));
    VkDeviceAddress write_partition_buffer_address = write_partition_buffer.Address();

    std::vector<VkBuildPartitionedAccelerationStructureIndirectCommandNV> ptlas_ops;
    VkBuildPartitionedAccelerationStructureIndirectCommandNV ptlas_op = {};
    ptlas_op.opType = VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_PARTITION_TRANSLATION_NV;
    ptlas_op.argCount = partition_count;
    ptlas_op.argData.startAddress = write_partition_buffer_address;
    ptlas_op.argData.strideInBytes = sizeof(VkPartitionedAccelerationStructureWriteInstanceDataNV);
    ptlas_ops.push_back(ptlas_op);

    vkt::Buffer src_info_buffer(*m_device, partition_count * sizeof(VkBuildPartitionedAccelerationStructureIndirectCommandNV),
                                VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                    VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                                vkt::device_address);
    auto* src_info_data = static_cast<VkBuildPartitionedAccelerationStructureIndirectCommandNV*>(src_info_buffer.Memory().Map());
    memcpy(src_info_data, ptlas_ops.data(), sizeof(VkBuildPartitionedAccelerationStructureIndirectCommandNV));
    VkDeviceAddress src_info_buffer_address = src_info_buffer.Address();

    vkt::Buffer count_buffer(*m_device, sizeof(uint32_t),
                             VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                             vkt::device_address);
    VkDeviceAddress count_buffer_address = count_buffer.Address();

    // Manually destroy memory to test memory validation
    build_buffer.Memory().Destroy();
    dst_build_buffer.Memory().Destroy();
    scratch_buffer.Memory().Destroy();
    src_info_buffer.Memory().Destroy();
    count_buffer.Memory().Destroy();

    VkBuildPartitionedAccelerationStructureInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.srcAccelerationStructureData = ptlas_buffer_address;
    command_info.dstAccelerationStructureData = dst_ptlas_buffer_address;
    command_info.scratchData = scratch_buffer_address;
    command_info.srcInfos = src_info_buffer_address;
    command_info.srcInfosCount = count_buffer_address;

    m_command_buffer.Begin();
    // For checking BuildPartitionedAccelerationStructureInfoNV memory bound
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    // For checking CmdBuildPartitionedAccelerationStructuresNV memory bound
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11279
TEST_F(NegativeRayTracing, DISABLED_CmdBuildPartitionedAccelerationStructures) {
    TEST_DESCRIPTION("Validate vkCmdBuildPartitionedAccelerationStructuresNV need partitionedAccelerationStructure feature");

    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    int instance_count = 20;
    int partition_count = 5;

    VkPartitionedAccelerationStructureInstancesInputNV input_info = vku::InitStructHelper();
    input_info.instanceCount = instance_count;
    input_info.maxInstancePerPartitionCount = instance_count / partition_count;
    input_info.partitionCount = partition_count;
    input_info.maxInstanceInGlobalPartitionCount = instance_count / partition_count;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;

    // constant size here is irrelevant, this test just check the feature enabled
    // Set a size smaller than VkAccelerationStructureBuildSizesInfoKHR::buildScratchSize to trigger the VU
    vkt::Buffer build_buffer(*m_device, 0x4,
                             VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                             vkt::device_address);
    VkDeviceAddress ptlas_buffer_address = build_buffer.Address();

    vkt::Buffer count_buffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
        vkt::device_address);
    // store the value into count buffer
    int input = instance_count;
    auto* data = static_cast<uint32_t*>(count_buffer.Memory().Map());
    memcpy(data, &input, sizeof(input));
    VkDeviceAddress count_buffer_address = count_buffer.Address();
    // constant size here is irrelevant, this test just check the feature enabled
    // Set a size smaller than VkAccelerationStructureBuildSizesInfoKHR:: to trigger the VU
    vkt::Buffer scratch_buffer(*m_device, 0x4,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                   VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);
    VkDeviceAddress scratch_buffer_address = scratch_buffer.Address();
    VkBuildPartitionedAccelerationStructureInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.srcAccelerationStructureData = 0;
    command_info.dstAccelerationStructureData = ptlas_buffer_address;
    command_info.scratchData = scratch_buffer_address;
    command_info.srcInfos = 0;
    command_info.srcInfosCount = count_buffer_address;
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-srcAccelerationStructureData-parameter");
    m_errorMonitor->SetDesiredError("VUID-VkBuildPartitionedAccelerationStructureInfoNV-srcInfos-parameter");
    vk::CmdBuildPartitionedAccelerationStructuresNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, PartitionedAccelerationStructuresBuildSizes) {
    TEST_DESCRIPTION(
        "Validate PartitionedAccelerationStructuresBuildSizes"
        "need to have partitionedAccelerationStructure feature enable "
        "and have valid VkPartitionedAccelerationStructureInstancesInputNV");

    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredExtensions(VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    int instance_count = 20;
    int partition_count = 5;

    VkPartitionedAccelerationStructureInstancesInputNV input_info = vku::InitStructHelper();
    input_info.instanceCount = instance_count;
    input_info.maxInstancePerPartitionCount = instance_count / partition_count;
    input_info.partitionCount = partition_count;
    input_info.maxInstanceInGlobalPartitionCount = instance_count / partition_count;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;
    VkAccelerationStructureBuildSizesInfoKHR ptlas_size_info = vku::InitStructHelper();
    m_errorMonitor->SetDesiredError(
        "VUID-vkGetPartitionedAccelerationStructuresBuildSizesNV-partitionedAccelerationStructure-10534");
    vk::GetPartitionedAccelerationStructuresBuildSizesNV(*m_device, &input_info, &ptlas_size_info);
    m_errorMonitor->VerifyFound();

    VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV partitioned_accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(partitioned_accel_struct_props);
    input_info.partitionCount = partitioned_accel_struct_props.maxPartitionCount;
    m_errorMonitor->SetDesiredError(
        "VUID-vkGetPartitionedAccelerationStructuresBuildSizesNV-partitionedAccelerationStructure-10534");
    m_errorMonitor->SetDesiredError("VUID-VkPartitionedAccelerationStructureInstancesInputNV-partitionCount-10535");
    vk::GetPartitionedAccelerationStructuresBuildSizesNV(*m_device, &input_info, &ptlas_size_info);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CmdBuildClusterAccelerationStructureIndirect) {
    TEST_DESCRIPTION("Validate vkCmdBuildClusterAccelerationStructureIndirect need clusterAccelerationStructures feature");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 1;
    uint32_t total_vertices = 3 * total_triangles;
    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;

    tri_cluster.maxClusterUniqueGeometryCount = 0;
    tri_cluster.maxClusterTriangleCount = total_triangles;
    tri_cluster.maxClusterVertexCount = total_vertices;

    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = total_vertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;
    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    // Create scratch_buffer constant size here is irrelevant, this test just checks the feature enabled
    vkt::Buffer scratch_buffer(*m_device, 0x1024,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                   VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);
    vkt::Buffer src_info_buffer(
        *m_device, sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    uint32_t input_num = 1;
    vkt::Buffer src_count_buffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    auto* count_data = static_cast<uint32_t*>(src_count_buffer.Memory().Map());
    memcpy(count_data, &input_num, sizeof(input_num));

    VkClusterAccelerationStructureCommandsInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.scratchData = scratch_buffer.Address();
    command_info.srcInfosArray.deviceAddress = src_info_buffer.Address();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    command_info.srcInfosCount = src_count_buffer.Address();

    vkt::Buffer implicit_build_buffer(*m_device, 0x1024,
                                      VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                          VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                          VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                                      vkt::device_address);

    vkt::Buffer dst_buffer(*m_device, 1 * sizeof(VkStridedDeviceAddressNV),
                           VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                               VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                           vkt::device_address);
    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstImplicitData = implicit_build_buffer.Address();
    command_info.dstAddressesArray.deviceAddress = dst_buffer.Address();
    command_info.dstAddressesArray.stride = sizeof(VkDeviceAddress);
    command_info.dstSizesArray.stride = sizeof(uint32_t);
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-clusterAccelerationStructure-10443");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CmdBuildClusterAccelerationStructureIndirectBadMemory) {
    TEST_DESCRIPTION("Validate vkCmdBuildClusterAccelerationStructureIndirectNV can not build with bad memory buffer");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 1;
    uint32_t totalVertices = 3 * total_triangles;

    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;
    tri_cluster.maxClusterUniqueGeometryCount = 0;
    tri_cluster.maxClusterTriangleCount = 1;
    tri_cluster.maxClusterVertexCount = 3;
    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = totalVertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;
    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    VkAccelerationStructureBuildSizesInfoKHR clas_size_info = vku::InitStructHelper();
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);

    vkt::Buffer scratch_buffer(*m_device, clas_size_info.buildScratchSize,
                               VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address);
    uint32_t index_data_f[10];
    for (uint32_t i = 0; i < 10; i++) {
        index_data_f[i] = i;
    }
    vkt::Buffer index_buffer(
        *m_device, 10 * sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    auto* index_data = static_cast<uint32_t*>(index_buffer.Memory().Map());
    memcpy(index_data, index_data_f, sizeof(index_data_f));

    vkt::Buffer src_info_buffer(
        *m_device, sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    const uint32_t numVerticesInCluster = totalVertices;
    VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV triClusterTemplateArg = {};
    triClusterTemplateArg.clusterID = 0;
    triClusterTemplateArg.clusterFlags = VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_ALLOW_DISABLE_OPACITY_MICROMAPS_NV;
    triClusterTemplateArg.triangleCount = total_triangles;
    triClusterTemplateArg.vertexCount = numVerticesInCluster;
    triClusterTemplateArg.positionTruncateBitCount = 0;
    triClusterTemplateArg.indexType = VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_32BIT_NV;
    triClusterTemplateArg.opacityMicromapIndexType = VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_32BIT_NV;
    triClusterTemplateArg.baseGeometryIndexAndGeometryFlags.geometryFlags =
        VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE_BIT_NV;
    triClusterTemplateArg.indexBufferStride = sizeof(uint32_t);
    triClusterTemplateArg.vertexBufferStride = 3 * sizeof(float);
    triClusterTemplateArg.geometryIndexAndFlagsBufferStride = 0;
    triClusterTemplateArg.opacityMicromapIndexBufferStride = 0;
    triClusterTemplateArg.indexBuffer = index_buffer.Address();
    triClusterTemplateArg.vertexBuffer = 0;
    triClusterTemplateArg.geometryIndexAndFlagsBuffer = 0;
    triClusterTemplateArg.opacityMicromapArray = 0;
    triClusterTemplateArg.opacityMicromapIndexBuffer = 0;
    triClusterTemplateArg.instantiationBoundingBoxLimit = 0;

    auto* src_info_data =
        static_cast<VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV*>(src_info_buffer.Memory().Map());
    memcpy(src_info_data, &triClusterTemplateArg, sizeof(triClusterTemplateArg));

    vkt::Buffer src_count_buffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    uint32_t input_num = 1;
    auto* count_data = static_cast<uint32_t*>(src_count_buffer.Memory().Map());
    memcpy(count_data, &input_num, sizeof(input_num));

    VkClusterAccelerationStructureCommandsInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.scratchData = scratch_buffer.Address();
    command_info.srcInfosArray.deviceAddress = src_info_buffer.Address();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    command_info.srcInfosCount = src_count_buffer.Address();

    vkt::Buffer implicit_build_buffer(
        *m_device, clas_size_info.accelerationStructureSize,
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, vkt::device_address);

    vkt::Buffer dstBuffer(*m_device, 1 * sizeof(VkStridedDeviceAddressNV),
                          VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address);

    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstImplicitData = implicit_build_buffer.Address();
    command_info.dstAddressesArray.deviceAddress = dstBuffer.Address();
    command_info.dstAddressesArray.stride = sizeof(VkDeviceAddress);
    command_info.dstSizesArray.deviceAddress = dstBuffer.Address();
    command_info.dstSizesArray.stride = sizeof(uint32_t);

    scratch_buffer.Memory().Destroy();
    src_info_buffer.Memory().Destroy();
    src_count_buffer.Memory().Destroy();
    implicit_build_buffer.Memory().Destroy();
    dstBuffer.Memory().Destroy();

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-None-10894");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, GetClusterAccelerationStructureBuildSizes) {
    TEST_DESCRIPTION("Validate all valid usages of vkGetClusterAccelerationStructureBuildSizesNV");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 10;
    uint32_t max_triangle_per_cluster = 10;
    uint32_t total_vertices = 3 * total_triangles;

    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;

    tri_cluster.maxClusterUniqueGeometryCount = max_triangle_per_cluster - 1;
    tri_cluster.maxClusterTriangleCount = max_triangle_per_cluster;
    tri_cluster.maxClusterVertexCount = max_triangle_per_cluster * 3;

    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = total_vertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;

    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    VkAccelerationStructureBuildSizesInfoKHR clas_size_info = vku::InitStructHelper();
    m_errorMonitor->SetDesiredError("VUID-vkGetClusterAccelerationStructureBuildSizesNV-clusterAccelerationStructure-10438");
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);
    m_errorMonitor->VerifyFound();
}

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11279
TEST_F(NegativeRayTracing, DISABLED_ClusterAccelerationStructureCommandsInfo) {
    TEST_DESCRIPTION("Validate ClusterAccelerationStructureCommandsInfo all valid usages");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 1;
    uint32_t total_vertices = 3 * total_triangles;

    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;

    tri_cluster.maxClusterUniqueGeometryCount = 0;
    tri_cluster.maxClusterTriangleCount = 1;
    tri_cluster.maxClusterVertexCount = 3;
    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = total_vertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;
    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    VkAccelerationStructureBuildSizesInfoKHR clas_size_info = vku::InitStructHelper();
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);

    vkt::Buffer scratch_buffer(*m_device, clas_size_info.buildScratchSize,
                               VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                   VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                               vkt::device_address);

    vkt::Buffer src_info_buffer(
        *m_device, sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    uint32_t input_num = 1;
    vkt::Buffer src_count_buffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    auto* count_data = static_cast<uint32_t*>(src_count_buffer.Memory().Map());
    memcpy(count_data, &input_num, sizeof(input_num));

    VkClusterAccelerationStructureCommandsInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.scratchData = scratch_buffer.Address();
    command_info.srcInfosArray.deviceAddress = src_info_buffer.Address();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    command_info.srcInfosCount = src_count_buffer.Address();

    vkt::Buffer implicit_build_buffer(
        *m_device, clas_size_info.accelerationStructureSize,
        VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR, vkt::device_address);

    vkt::Buffer dst_buffer(*m_device, 1 * sizeof(VkStridedDeviceAddressNV),
                           VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address);

    vkt::Buffer countBuffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstImplicitData = implicit_build_buffer.Address();
    command_info.dstAddressesArray.deviceAddress = dst_buffer.Address();
    command_info.dstAddressesArray.stride = sizeof(VkDeviceAddress);
    command_info.dstSizesArray.stride = sizeof(uint32_t);

    m_command_buffer.Begin();

    command_info.dstImplicitData = 0;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-dstImplicitData-parameter");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_build_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-opMode-12312");
    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_COMPUTE_SIZES_NV;
    command_info.dstSizesArray.deviceAddress = 0;
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstSizesArray.deviceAddress = countBuffer.Address();
    command_info.dstAddressesArray.stride = 7;
    command_info.dstSizesArray.stride = 3;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-dstAddressesArray-10474");
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-dstSizesArray-10475");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstAddressesArray.stride = sizeof(VkDeviceAddress);
    command_info.dstSizesArray.stride = 4;
    m_command_buffer.End();

    VkPhysicalDeviceClusterAccelerationStructurePropertiesNV accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);
    m_command_buffer.Begin();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV) - 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-srcInfosArray-10476");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.dstImplicitData = implicit_build_buffer.Address() / accel_struct_props.clusterTemplateByteAlignment *
                                       accel_struct_props.clusterTemplateByteAlignment +
                                   1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-input-12318");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_build_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.scratchData = (scratch_buffer.Address() / accel_struct_props.clusterScratchByteAlignment) *
                                   accel_struct_props.clusterScratchByteAlignment +
                               1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-scratchData-12320");
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-scratchData-12301");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.scratchData = scratch_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.dstImplicitData = scratch_buffer.Address();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-dstImplicitData-12303");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_build_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.dstAddressesArray.deviceAddress = scratch_buffer.Address();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-dstAddressesArray-12302");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstAddressesArray.deviceAddress = dst_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    command_info.srcInfosCount = (src_count_buffer.Address() / 4) * 4 + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-srcInfosCount-12322");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.srcInfosCount = src_count_buffer.Address();
    m_command_buffer.End();

    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
    input_info.opInput = input;
    command_info.input = input_info;

    m_command_buffer.Begin();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterInfoNV) - 1;
    command_info.dstImplicitData =
        implicit_build_buffer.Address() / accel_struct_props.clusterByteAlignment * accel_struct_props.clusterByteAlignment + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-srcInfosArray-10476");
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-input-12317");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_build_buffer.Address();
    m_command_buffer.End();

    input_info.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_INSTANTIATE_TRIANGLE_CLUSTER_NV;
    input_info.opInput = input;
    command_info.input = input_info;
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureInstantiateClusterInfoNV);

    m_command_buffer.Begin();
    command_info.dstImplicitData =
        implicit_build_buffer.Address() / accel_struct_props.clusterByteAlignment * accel_struct_props.clusterByteAlignment + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-input-12319");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_build_buffer.Address();
    m_command_buffer.End();

    m_command_buffer.Begin();
    input_info.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_EXPLICIT_DESTINATIONS_NV;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;
    command_info.input = input_info;
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    command_info.dstImplicitData = implicit_build_buffer.Address();
    command_info.dstAddressesArray.deviceAddress = 0;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-opMode-12313");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, ClusterAccelerationStructureTriangleClusterInput) {
    TEST_DESCRIPTION("Validate all valid usages of VkClusterAccelerationStructureTriangleClusterInputNV");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 10;
    uint32_t max_triangle_per_cluster = 10;
    uint32_t total_vertices = 3 * total_triangles;
    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;

    tri_cluster.maxClusterUniqueGeometryCount = max_triangle_per_cluster - 1;
    tri_cluster.maxClusterTriangleCount = max_triangle_per_cluster;
    tri_cluster.maxClusterVertexCount = max_triangle_per_cluster * 3;

    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = total_vertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;

    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    tri_cluster.vertexFormat = VK_FORMAT_R32_SFLOAT;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-vertexFormat-10439");
    VkAccelerationStructureBuildSizesInfoKHR clas_size_info = vku::InitStructHelper();
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;

    VkPhysicalDeviceClusterAccelerationStructurePropertiesNV accel_struct_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(accel_struct_props);
    tri_cluster.maxClusterTriangleCount = accel_struct_props.maxTrianglesPerCluster + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-maxClusterTriangleCount-10440");
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.maxClusterTriangleCount = max_triangle_per_cluster;

    tri_cluster.maxClusterVertexCount = accel_struct_props.maxVerticesPerCluster + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-maxClusterVertexCount-10441");
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.maxClusterVertexCount = max_triangle_per_cluster * 3;

    tri_cluster.minPositionTruncateBitCount = 33;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-minPositionTruncateBitCount-10442");
    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.minPositionTruncateBitCount = 0;

    vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &clas_size_info);

    vkt::Buffer scratch_buffer(*m_device, clas_size_info.buildScratchSize,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                   VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);

    vkt::Buffer src_info_buffer(
        *m_device, sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    uint32_t input_num = 1;
    vkt::Buffer src_count_buffer(
        *m_device, sizeof(uint32_t),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);
    auto* count_data = static_cast<uint32_t*>(src_count_buffer.Memory().Map());
    memcpy(count_data, &input_num, sizeof(input_num));

    vkt::Buffer implicit_buffer(*m_device, clas_size_info.accelerationStructureSize + 256,
                                VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                    VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                    VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                                vkt::device_address);

    VkClusterAccelerationStructureCommandsInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.scratchData = scratch_buffer.Address();
    command_info.srcInfosArray.deviceAddress = src_info_buffer.Address();
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);
    command_info.srcInfosCount = src_count_buffer.Address();
    command_info.dstImplicitData = implicit_buffer.Address();

    m_command_buffer.Begin();

    tri_cluster.vertexFormat = VK_FORMAT_R32_SFLOAT;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-vertexFormat-10439");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;

    tri_cluster.maxClusterTriangleCount = accel_struct_props.maxTrianglesPerCluster + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-maxClusterTriangleCount-10440");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.maxClusterTriangleCount = max_triangle_per_cluster;

    tri_cluster.maxClusterVertexCount = accel_struct_props.maxVerticesPerCluster + 1;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-maxClusterVertexCount-10441");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();
    tri_cluster.maxClusterVertexCount = max_triangle_per_cluster * 3;
    tri_cluster.minPositionTruncateBitCount = 33;
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-minPositionTruncateBitCount-10442");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, ClusterAccelerationStructureTriangleClusterStatelessValidation) {
    TEST_DESCRIPTION("Test stateless validation of VkClusterAccelerationStructureTriangleClusterInputNV sType and pNext");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    {
        VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
        tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
        tri_cluster.maxClusterTriangleCount = 1;
        tri_cluster.maxClusterVertexCount = 3;

        VkDeviceCreateInfo invalid_pnext = vku::InitStructHelper();
        tri_cluster.pNext = &invalid_pnext;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = &tri_cluster;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-pNext-pNext");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
        tri_cluster.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;  // Wrong sType
        tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
        tri_cluster.maxClusterTriangleCount = 1;
        tri_cluster.maxClusterVertexCount = 3;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = &tri_cluster;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-sType-sType");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkBufferCreateInfo invalid_pnext = vku::InitStructHelper();
        VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper(&invalid_pnext);
        tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
        tri_cluster.maxClusterTriangleCount = 1;
        tri_cluster.maxClusterVertexCount = 3;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = &tri_cluster;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-pNext-pNext");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
    {
        VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
        // Invalid enum value
        tri_cluster.vertexFormat = static_cast<VkFormat>(999);
        tri_cluster.maxClusterTriangleCount = 1;
        tri_cluster.maxClusterVertexCount = 3;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = &tri_cluster;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureTriangleClusterInputNV-vertexFormat-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, ClusterAccelerationStructureMoveObjectsStatelessValidation) {
    TEST_DESCRIPTION("Test stateless validation of VkClusterAccelerationStructureMoveObjectsInputNV sType, pNext, and type enum");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());
    {
        VkClusterAccelerationStructureMoveObjectsInputNV move_objects = vku::InitStructHelper();
        move_objects.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        move_objects.type = VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_NV;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pMoveObjects = &move_objects;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureMoveObjectsInputNV-sType-sType");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
    {
        VkBufferCreateInfo invalid_pnext = vku::InitStructHelper();
        VkClusterAccelerationStructureMoveObjectsInputNV move_objects = vku::InitStructHelper(&invalid_pnext);
        move_objects.type = VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_NV;

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pMoveObjects = &move_objects;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureMoveObjectsInputNV-pNext-pNext");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
    {
        VkClusterAccelerationStructureMoveObjectsInputNV move_objects = vku::InitStructHelper();
        // Invalid enum value
        move_objects.type = static_cast<VkClusterAccelerationStructureTypeNV>(999);

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pMoveObjects = &move_objects;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureMoveObjectsInputNV-type-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, ClusterAccelerationStructureClustersBottomLevelStatelessValidation) {
    TEST_DESCRIPTION("Test stateless validation of VkClusterAccelerationStructureClustersBottomLevelInputNV sType and pNext");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    {
        VkClusterAccelerationStructureClustersBottomLevelInputNV bottom_level = vku::InitStructHelper();
        bottom_level.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;  // Wrong sType

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pClustersBottomLevel = &bottom_level;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureClustersBottomLevelInputNV-sType-sType");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
    {
        VkBufferCreateInfo invalid_pnext = vku::InitStructHelper();
        VkClusterAccelerationStructureClustersBottomLevelInputNV bottom_level = vku::InitStructHelper(&invalid_pnext);

        VkClusterAccelerationStructureOpInputNV input = {};
        input.pClustersBottomLevel = &bottom_level;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureClustersBottomLevelInputNV-pNext-pNext");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, ClusterAccelerationStructureInputInfoOpInputPointerValidation) {
    TEST_DESCRIPTION("Test pointer validation for VkClusterAccelerationStructureInputInfoNV opInput");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pClustersBottomLevel = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pClustersBottomLevel-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pTriangleClusters-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pTriangleClusters-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_INSTANTIATE_TRIANGLE_CLUSTER_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pTriangleClusters-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pTriangleClusters = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_GET_CLUSTER_TEMPLATE_INDICES_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pTriangleClusters-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }

    {
        VkClusterAccelerationStructureOpInputNV input = {};
        input.pMoveObjects = nullptr;

        VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
        input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV;
        input_info.opInput = input;

        VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
        m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureInputInfoNV-pMoveObjects-parameter");
        vk::GetClusterAccelerationStructureBuildSizesNV(*m_device, &input_info, &size_info);
        m_errorMonitor->VerifyFound();
    }
}

TEST_F(NegativeRayTracing, CmdBuildClusterAccelerationStructureIndirectValidation) {
    TEST_DESCRIPTION("Test various validation rules for vkCmdBuildClusterAccelerationStructureIndirectNV");
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    AddRequiredFeature(vkt::Feature::clusterAccelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint32_t total_triangles = 1;
    uint32_t total_vertices = 3 * total_triangles;
    VkClusterAccelerationStructureTriangleClusterInputNV tri_cluster = vku::InitStructHelper();
    tri_cluster.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
    tri_cluster.maxGeometryIndexValue = total_triangles - 1;
    tri_cluster.maxClusterUniqueGeometryCount = 0;
    tri_cluster.maxClusterTriangleCount = total_triangles;
    tri_cluster.maxClusterVertexCount = total_vertices;
    tri_cluster.maxTotalTriangleCount = total_triangles;
    tri_cluster.maxTotalVertexCount = total_vertices;
    tri_cluster.minPositionTruncateBitCount = 0;

    VkClusterAccelerationStructureOpInputNV input = {};
    input.pTriangleClusters = &tri_cluster;
    VkClusterAccelerationStructureInputInfoNV input_info = vku::InitStructHelper();
    input_info.maxAccelerationStructureCount = 1;
    input_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
    input_info.opType = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV;
    input_info.opInput = input;

    VkAccelerationStructureBuildSizesInfoKHR size_info = vku::InitStructHelper();
    vk::GetClusterAccelerationStructureBuildSizesNV(m_device->handle(), &input_info, &size_info);

    vkt::Buffer scratch_buffer_wrong_usage(
        *m_device, size_info.buildScratchSize,
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
        vkt::device_address);

    vkt::Buffer scratch_buffer(*m_device, size_info.buildScratchSize,
                               VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                   VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                               vkt::device_address);

    vkt::Buffer small_scratch_buffer(*m_device, size_info.buildScratchSize - 100,
                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                         VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
                                     vkt::device_address);

    vkt::Buffer dst_buffer_wrong_usage(*m_device, size_info.accelerationStructureSize,
                                       VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                                       vkt::device_address);
    vkt::Buffer count_buffer(*m_device, sizeof(uint32_t),
                             VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
                             vkt::device_address);
    vkt::Buffer implicit_buffer(*m_device, size_info.accelerationStructureSize,
                                VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                    VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
                                    VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                                vkt::device_address);

    auto* data = static_cast<uint32_t*>(count_buffer.Memory().Map());
    memcpy(data, &total_triangles, sizeof(total_triangles));
    VkDeviceAddress count_buffer_address = count_buffer.Address();

    VkClusterAccelerationStructureCommandsInfoNV command_info = vku::InitStructHelper();
    command_info.input = input_info;
    command_info.scratchData = scratch_buffer_wrong_usage.Address();
    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstImplicitData = implicit_buffer.Address();
    command_info.srcInfosCount = count_buffer_address;
    command_info.srcInfosArray.stride = sizeof(VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-pCommandInfos-12304");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();

    command_info.scratchData = scratch_buffer.Address();
    command_info.dstImplicitData = dst_buffer_wrong_usage.Address();
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-pCommandInfos-12308");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();

    vkt::Buffer count_buffer_wrong_usage(*m_device, sizeof(uint32_t),
                                         VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
                                         vkt::device_address);
    auto* data_wrong = static_cast<uint32_t*>(count_buffer_wrong_usage.Memory().Map());
    memcpy(data_wrong, &total_triangles, sizeof(total_triangles));
    command_info.dstImplicitData = implicit_buffer.Address();
    command_info.srcInfosCount = count_buffer_wrong_usage.Address();
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-pCommandInfos-12306");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();
    command_info.srcInfosCount = count_buffer_address;

    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_EXPLICIT_DESTINATIONS_NV;
    vkt::Buffer dst_addresses_buffer_wrong_usage(
        *m_device, sizeof(VkDeviceAddress),
        VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, vkt::device_address);
    command_info.dstAddressesArray.deviceAddress = dst_addresses_buffer_wrong_usage.Address();
    command_info.dstAddressesArray.stride = sizeof(VkDeviceAddress);
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-pCommandInfos-12381");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();
    command_info.input.opMode = VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV;
    command_info.dstAddressesArray.deviceAddress = 0;

    vkt::Buffer dst_buffer_small(*m_device, size_info.accelerationStructureSize - 100,
                                 VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
                                     VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
                                     VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
                                 vkt::device_address);
    command_info.dstImplicitData = dst_buffer_small.Address();

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkClusterAccelerationStructureCommandsInfoNV-opMode-12310");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();
    command_info.dstImplicitData = implicit_buffer.Address();

    command_info.scratchData = small_scratch_buffer.Address();
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-scratchData-12300");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();
    command_info.scratchData = scratch_buffer.Address();

    const vkt::PipelineLayout pipeline_layout(*m_device, {});
    VkPipeline raytracing_pipeline = VK_NULL_HANDLE;
    {
        VkShaderObj rgen_shader(*m_device, kRayTracingMinimalGlsl, VK_SHADER_STAGE_RAYGEN_BIT_KHR, SPV_ENV_VULKAN_1_2);
        VkShaderObj chit_shader(*m_device, kRayTracingMinimalGlsl, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, SPV_ENV_VULKAN_1_2);

        std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages;
        shader_stages[0] = vku::InitStructHelper();
        shader_stages[0].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
        shader_stages[0].module = chit_shader;
        shader_stages[0].pName = "main";

        shader_stages[1] = vku::InitStructHelper();
        shader_stages[1].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
        shader_stages[1].module = rgen_shader;
        shader_stages[1].pName = "main";

        std::array<VkRayTracingShaderGroupCreateInfoKHR, 1> shader_groups;
        shader_groups[0] = vku::InitStructHelper();
        shader_groups[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
        shader_groups[0].generalShader = 1;
        shader_groups[0].closestHitShader = VK_SHADER_UNUSED_KHR;
        shader_groups[0].anyHitShader = VK_SHADER_UNUSED_KHR;
        shader_groups[0].intersectionShader = VK_SHADER_UNUSED_KHR;
        VkRayTracingPipelineCreateInfoKHR raytracing_pipeline_ci = vku::InitStructHelper();
        raytracing_pipeline_ci.flags = 0;
        raytracing_pipeline_ci.stageCount = static_cast<uint32_t>(shader_stages.size());
        raytracing_pipeline_ci.pStages = shader_stages.data();
        raytracing_pipeline_ci.pGroups = shader_groups.data();
        raytracing_pipeline_ci.groupCount = shader_groups.size();
        raytracing_pipeline_ci.layout = pipeline_layout;
        raytracing_pipeline_ci.maxPipelineRayRecursionDepth = 1;

        const VkResult result = vk::CreateRayTracingPipelinesKHR(*m_device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1,
                                                                 &raytracing_pipeline_ci, nullptr, &raytracing_pipeline);
        ASSERT_EQ(VK_SUCCESS, result);
    }

    m_command_buffer.Begin();
    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, raytracing_pipeline);
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildClusterAccelerationStructureIndirectNV-pNext-10444");
    vk::CmdBuildClusterAccelerationStructureIndirectNV(m_command_buffer, &command_info);
    m_command_buffer.End();
    m_errorMonitor->VerifyFound();

    vk::DestroyPipeline(device(), raytracing_pipeline, nullptr);
}

TEST_F(NegativeRayTracing, DescriptorBuffers) {
    SetTargetApiVersion(VK_API_VERSION_1_3);
    AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::descriptorBuffer);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_properties = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(descriptor_buffer_properties);

    uint8_t buffer[256];  // (max accelerationStructureDescriptorSize)
    VkDescriptorGetInfoEXT dgi = vku::InitStructHelper();
    dgi.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
    dgi.data.accelerationStructure = 0xbaadbeef;
    m_errorMonitor->SetDesiredError("VUID-VkDescriptorGetInfoEXT-type-08028");
    vk::GetDescriptorEXT(device(), &dgi, descriptor_buffer_properties.accelerationStructureDescriptorSize, &buffer);
    m_errorMonitor->VerifyFound();

    // This is getting underyling buffer, not the acceleration structure
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    dgi.data.accelerationStructure = tlas.GetDstAS()->GetBufferDeviceAddress();
    m_errorMonitor->SetDesiredError("VUID-VkDescriptorGetInfoEXT-type-08028");
    vk::GetDescriptorEXT(device(), &dgi, descriptor_buffer_properties.accelerationStructureDescriptorSize, &buffer);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, WriteResourceAccelerationStructure) {
    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::descriptorHeap);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
    GetPhysicalDeviceProperties2(heap_props);

    const VkDeviceSize descriptor_size =
        vk::GetPhysicalDeviceDescriptorSizeEXT(gpu_, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
    std::vector<uint8_t> data(static_cast<size_t>(descriptor_size));

    vkt::Buffer buffer(*m_device, 256, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, vkt::device_address);
    VkDeviceAddressRangeEXT device_address_range = buffer.AddressRange();

    VkResourceDescriptorInfoEXT resource_info = vku::InitStructHelper();
    resource_info.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
    resource_info.data.pAddressRange = &device_address_range;

    VkHostAddressRangeEXT descriptor = {data.data(), static_cast<size_t>(descriptor_size)};
    // May not be aligned as required, but that is not focus of test
    m_errorMonitor->SetAllowedFailureMsg("VUID-VkResourceDescriptorInfoEXT-type-11454");
    m_errorMonitor->SetDesiredError("VUID-VkResourceDescriptorInfoEXT-type-11483");
    vk::WriteResourceDescriptorsEXT(*m_device, 1u, &resource_info, &descriptor);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, DescriptorHeapUsingWrongBuffer) {
    SetTargetApiVersion(VK_API_VERSION_1_2);
    AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::descriptorHeap);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    uint8_t host_descriptor_data[4096];  // enought to hold |descriptor_size|
    const VkDeviceSize descriptor_size =
        vk::GetPhysicalDeviceDescriptorSizeEXT(gpu_, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);

    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));

    // This is getting underyling buffer, not the acceleration structure
    VkDeviceAddress tlas_device_address = tlas.GetDstAS()->GetBufferDeviceAddress();
    VkDeviceAddressRangeEXT device_address_range = {tlas_device_address, 0};

    VkResourceDescriptorInfoEXT resource_info = vku::InitStructHelper();
    resource_info.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
    resource_info.data.pAddressRange = &device_address_range;

    VkHostAddressRangeEXT descriptor = {host_descriptor_data, static_cast<size_t>(descriptor_size)};
    m_errorMonitor->SetDesiredError("VUID-VkResourceDescriptorInfoEXT-type-11483");
    vk::WriteResourceDescriptorsEXT(*m_device, 1u, &resource_info, &descriptor);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, MisalignedPrimitiveOffset) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device));
    vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube));

    auto build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].primitiveOffset = 1;
    cube_blas.SetBuildRanges(build_range_infos);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-primitiveOffset-03656");
    cube_blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, MisalignedPrimitiveOffset2) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].SetTrianglesIndexType(VK_INDEX_TYPE_NONE_KHR);

    auto build_range_infos = blas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].primitiveOffset = 1;
    blas.SetBuildRanges(build_range_infos);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-primitiveOffset-03657");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, MisalignedPrimitiveOffset3) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device));
    vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube));

    auto build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].transformOffset = 1;
    cube_blas.SetBuildRanges(build_range_infos);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-transformOffset-03658");
    cube_blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, MisalignedPrimitiveOffset4) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0] = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device);

    auto build_range_infos = blas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].primitiveOffset = 1;
    blas.SetBuildRanges(build_range_infos);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-primitiveOffset-03659");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, MisalignedPrimitiveOffset5) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);

    m_command_buffer.Begin();
    blas.BuildCmdBuffer(m_command_buffer);
    m_command_buffer.End();

    m_default_queue->Submit(m_command_buffer);
    m_device->Wait();

    vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS());
    auto build_range_infos = tlas.GetBuildRangeInfosFromGeometries();
    build_range_infos[0].primitiveOffset = 1;
    tlas.SetBuildRanges(build_range_infos);

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureBuildRangeInfoKHR-primitiveOffset-03660");
    tlas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, DestroyedDeviceAddressRange) {
    SetTargetApiVersion(VK_API_VERSION_1_2);

    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayTracingPipeline);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::rt::Pipeline rt_pipeline(*this, m_device);

    rt_pipeline.SetGlslRayGenShader(kRayTracingMinimalGlsl);

    rt_pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl);
    rt_pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl);

    rt_pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
    rt_pipeline.CreateDescriptorSet();
    vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
    rt_pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
    rt_pipeline.GetDescriptorSet().UpdateDescriptorSets();

    rt_pipeline.Build();

    vkt::rt::TraceRaysSbt sbt = rt_pipeline.GetTraceRaysSbt();

    m_command_buffer.Begin();
    vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rt_pipeline);
    vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &sbt.miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
    VkStridedDeviceAddressRegionKHR null_addr_miss_sbt = sbt.miss_sbt;
    null_addr_miss_sbt.deviceAddress = 0;
    vk::CmdTraceRaysKHR(m_command_buffer, &sbt.ray_gen_sbt, &null_addr_miss_sbt, &sbt.hit_sbt, &sbt.callable_sbt, 100, 100, 1);
    m_command_buffer.End();

    rt_pipeline.DestroySbtBuffer();

    m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
    m_default_queue->SubmitAndWait(m_command_buffer);
    m_errorMonitor->VerifyFound();
}

TEST_F(NegativeRayTracing, CopyUnboundAccelerationStructure2KHR) {
    TEST_DESCRIPTION(
        "Test CmdCopyAccelerationStructureKHR with AS created with version 2 of create info, and the buffer backing either src or "
        "dst has been destroyed.");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::deviceAddressCommands);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas_no_buf = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas_no_buf->SetCreateWithVersion2(true);
    blas_no_buf->SetAddressFlags(VK_ADDRESS_COMMAND_STORAGE_BUFFER_USAGE_BIT_KHR);
    blas_no_buf->Create();
    blas_no_buf->GetBuffer().Destroy();

    auto valid_blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    valid_blas->SetCreateWithVersion2(true);
    valid_blas->SetAddressFlags(VK_ADDRESS_COMMAND_STORAGE_BUFFER_USAGE_BIT_KHR);
    valid_blas->Create();

    VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas_no_buf->handle();
    copy_info.dst = valid_blas->handle();
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;

    m_command_buffer.Begin();

    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    copy_info.src = valid_blas->handle();
    copy_info.dst = blas_no_buf->handle();
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
    vk::CmdCopyAccelerationStructureKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CmdCopyAccelerationStructureToMemory2KHR) {
    TEST_DESCRIPTION(
        "vkCmdCopyAccelerationStructureToMemoryKHR with src AS created with version 2 of create info, "
        "where the backing buffer has been destroyed");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::deviceAddressCommands);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    auto blas_no_buf = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
    blas_no_buf->SetCreateWithVersion2(true);
    blas_no_buf->SetAddressFlags(VK_ADDRESS_COMMAND_STORAGE_BUFFER_USAGE_BIT_KHR);
    blas_no_buf->Create();
    blas_no_buf->GetBuffer().Destroy();

    VkDeviceOrHostAddressKHR dst_addr{};
    dst_addr.deviceAddress = Align<VkDeviceAddress>(0xbaadbeef, 256);
    VkCopyAccelerationStructureToMemoryInfoKHR copy_info = vku::InitStructHelper();
    copy_info.src = blas_no_buf->handle();
    copy_info.dst = dst_addr;
    copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;

    m_command_buffer.Begin();

    // duplicate errors due to questionable spec design
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-11714");
    m_errorMonitor->SetDesiredError("VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-11715");
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    vk::CmdCopyAccelerationStructureToMemoryKHR(m_command_buffer, &copy_info);
    m_errorMonitor->VerifyFound();

    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, CreateInfo2DestroyBuffer) {
    TEST_DESCRIPTION("Use create info version 2, destroy buffer after creation and try to use AS in a build");

    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
    AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::deviceAddressCommands);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    AddRequiredFeature(vkt::Feature::rayQuery);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetDstAS()->SetCreateWithVersion2(true);
    blas.GetDstAS()->SetAddressFlags(VK_ADDRESS_COMMAND_STORAGE_BUFFER_USAGE_BIT_KHR);
    blas.GetDstAS()->Create();

    blas.GetDstAS()->GetBuffer().Destroy();

    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03707");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}

TEST_F(NegativeRayTracing, GeometryMotionTrianglesDataNV) {
    SetTargetApiVersion(VK_API_VERSION_1_1);
    AddRequiredExtensions(VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME);
    AddRequiredFeature(vkt::Feature::rayTracingMotionBlur);
    AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
    AddRequiredFeature(vkt::Feature::accelerationStructure);
    RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
    RETURN_IF_SKIP(InitState());

    VkAccelerationStructureGeometryMotionTrianglesDataNV motion_triangles = vku::InitStructHelper();
    motion_triangles.vertexData.deviceAddress = 0xbaadbeef;
    vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
    blas.GetGeometries()[0].GetVkObj().geometry.triangles.pNext = &motion_triangles;
    m_command_buffer.Begin();
    m_errorMonitor->SetDesiredError("VUID-VkDeviceAddress-size-11364");
    blas.BuildCmdBuffer(m_command_buffer);
    m_errorMonitor->VerifyFound();
    m_command_buffer.End();
}
