blob: 935d70d15313253fdc48f2bf8f23dfd2f78d9d4a [file]
/*
* 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) 2022 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <gtest/gtest.h>
#include <vulkan/vulkan_core.h>
#include "utils/math_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
class NegativeDeviceAddress : public VkLayerTest {};
TEST_F(NegativeDeviceAddress, DestroyOnlyBuffer) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
const size_t copy_size = sizeof(VkCopyMemoryIndirectCommandKHR);
vkt::Buffer indirect_buffer(*m_device, copy_size, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
VkStridedDeviceAddressRangeKHR copy_address_range = {};
copy_address_range.address = indirect_buffer.Address();
copy_address_range.stride = copy_size;
copy_address_range.size = copy_size;
VkCopyMemoryIndirectInfoKHR indirect_info = vku::InitStructHelper();
indirect_info.copyCount = 1u;
indirect_info.copyAddressRange = copy_address_range;
m_command_buffer.Begin();
vk::CmdCopyMemoryIndirectKHR(m_command_buffer, &indirect_info);
m_command_buffer.End();
indirect_buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, DestroyAllBuffers) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
const size_t copy_size = sizeof(VkCopyMemoryIndirectCommandKHR);
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = copy_size;
buffer_ci.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer indirect_buffer1(*m_device, buffer_ci, vkt::no_mem);
vkt::Buffer indirect_buffer2(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, indirect_buffer1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
memory_ai.allocationSize = memory_requirements.size;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, indirect_buffer1, memory, 0);
vk::BindBufferMemory(*m_device, indirect_buffer2, memory, 0);
VkDeviceAddress address1 = indirect_buffer1.Address();
VkDeviceAddress address2 = indirect_buffer2.Address();
if (address1 != address2) {
GTEST_SKIP() << "Device addresses are not equal.";
}
VkStridedDeviceAddressRangeKHR copy_address_range = {};
copy_address_range.address = indirect_buffer1.Address();
copy_address_range.stride = copy_size;
copy_address_range.size = copy_size;
VkCopyMemoryIndirectInfoKHR indirect_info = vku::InitStructHelper();
indirect_info.copyCount = 1u;
indirect_info.copyAddressRange = copy_address_range;
m_command_buffer.Begin();
vk::CmdCopyMemoryIndirectKHR(m_command_buffer, &indirect_info);
m_command_buffer.End();
indirect_buffer1.Destroy();
indirect_buffer2.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, GetSecondDeviceAddressAfterInvalidation) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
const size_t copy_size = sizeof(VkCopyMemoryIndirectCommandKHR);
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = copy_size;
buffer_ci.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer indirect_buffer1(*m_device, buffer_ci, vkt::no_mem);
vkt::Buffer indirect_buffer2(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, indirect_buffer1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
memory_ai.allocationSize = memory_requirements.size;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, indirect_buffer1, memory, 0);
vk::BindBufferMemory(*m_device, indirect_buffer2, memory, 0);
VkDeviceAddress address1 = indirect_buffer1.Address();
VkStridedDeviceAddressRangeKHR copy_address_range = {};
copy_address_range.address = indirect_buffer1.Address();
copy_address_range.stride = copy_size;
copy_address_range.size = copy_size;
VkCopyMemoryIndirectInfoKHR indirect_info = vku::InitStructHelper();
indirect_info.copyCount = 1u;
indirect_info.copyAddressRange = copy_address_range;
m_command_buffer.Begin();
vk::CmdCopyMemoryIndirectKHR(m_command_buffer, &indirect_info);
m_command_buffer.End();
indirect_buffer1.Destroy();
VkDeviceAddress address2 = indirect_buffer2.Address();
if (address1 != address2) {
GTEST_SKIP() << "Device addresses are not equal.";
}
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, SecondBufferUnrelatedUsage) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
const size_t copy_size = sizeof(VkCopyMemoryIndirectCommandKHR);
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = copy_size;
buffer_ci.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer indirect_buffer1(*m_device, buffer_ci, vkt::no_mem);
buffer_ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer indirect_buffer2(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, indirect_buffer1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
memory_ai.allocationSize = memory_requirements.size;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, indirect_buffer1, memory, 0);
vk::BindBufferMemory(*m_device, indirect_buffer2, memory, 0);
VkDeviceAddress address1 = indirect_buffer1.Address();
VkDeviceAddress address2 = indirect_buffer2.Address();
if (address1 != address2) {
GTEST_SKIP() << "Device addresses are not equal.";
}
VkStridedDeviceAddressRangeKHR copy_address_range = {};
copy_address_range.address = indirect_buffer1.Address();
copy_address_range.stride = copy_size;
copy_address_range.size = copy_size;
VkCopyMemoryIndirectInfoKHR indirect_info = vku::InitStructHelper();
indirect_info.copyCount = 1u;
indirect_info.copyAddressRange = copy_address_range;
m_command_buffer.Begin();
vk::CmdCopyMemoryIndirectKHR(m_command_buffer, &indirect_info);
m_command_buffer.End();
indirect_buffer1.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, DestroyBeforeCmdBufferEnd) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
const size_t copy_size = sizeof(VkCopyMemoryIndirectCommandKHR);
vkt::Buffer indirect_buffer(*m_device, copy_size, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
VkStridedDeviceAddressRangeKHR copy_address_range = {};
copy_address_range.address = indirect_buffer.Address();
copy_address_range.stride = copy_size;
copy_address_range.size = copy_size;
VkCopyMemoryIndirectInfoKHR indirect_info = vku::InitStructHelper();
indirect_info.copyCount = 1u;
indirect_info.copyAddressRange = copy_address_range;
m_command_buffer.Begin();
vk::CmdCopyMemoryIndirectKHR(m_command_buffer, &indirect_info);
indirect_buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkEndCommandBuffer-commandBuffer-00059");
vk::EndCommandBuffer(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, MemoryToImageIndirect) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryToImageCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
VkCopyMemoryToImageIndirectCommandKHR cmd1 = {};
cmd1.srcAddress = 0;
cmd1.bufferRowLength = 8;
cmd1.bufferImageHeight = 8;
cmd1.imageSubresource = {};
cmd1.imageOffset = {0, 0, 0};
cmd1.imageExtent = {8, 8, 1};
VkCopyMemoryToImageIndirectCommandKHR cmd2 = {};
cmd2.srcAddress = 1024;
cmd2.bufferRowLength = 4;
cmd2.bufferImageHeight = 4;
cmd2.imageSubresource = {};
cmd2.imageOffset = {0, 0, 0};
cmd2.imageExtent = {4, 4, 1};
VkCopyMemoryToImageIndirectCommandKHR cmds[2] = {cmd1, cmd2};
vkt::Buffer indirect_buffer(*m_device, sizeof(cmds), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
VkImageSubresourceLayers res_layer = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceLayers res_layers[2] = {res_layer, res_layer};
m_command_buffer.Begin();
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 4;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_create_info.flags = 0;
vkt::Image src_image(*m_device, image_create_info, vkt::set_layout);
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
vkt::Image dst_image(*m_device, image_create_info, vkt::set_layout);
VkImageCopy copy_region;
copy_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.dstSubresource = copy_region.srcSubresource;
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
copy_region.extent = {1, 1, 1};
const uint32_t stride = sizeof(VkCopyMemoryToImageIndirectCommandKHR);
VkStridedDeviceAddressRangeKHR address_range = {};
address_range.address = indirect_buffer.Address();
address_range.size = sizeof(cmds);
address_range.stride = stride;
VkCopyMemoryToImageIndirectInfoKHR copy_info = vku::InitStructHelper();
copy_info.copyCount = 2;
copy_info.copyAddressRange = address_range;
copy_info.srcCopyFlags = VK_ADDRESS_COPY_DEVICE_LOCAL_BIT_KHR;
copy_info.dstImage = dst_image;
copy_info.dstImageLayout = VK_IMAGE_LAYOUT_GENERAL;
copy_info.pImageSubresources = res_layers;
vk::CmdCopyImage(m_command_buffer, src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
vk::CmdCopyMemoryToImageIndirectKHR(m_command_buffer, &copy_info);
m_command_buffer.End();
indirect_buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, MultipleBrokenRanges) {
AddRequiredExtensions(VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::indirectMemoryToImageCopy);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
VkCopyMemoryToImageIndirectCommandKHR cmd1 = {};
cmd1.srcAddress = 0;
cmd1.bufferRowLength = 8;
cmd1.bufferImageHeight = 8;
cmd1.imageSubresource = {};
cmd1.imageOffset = {0, 0, 0};
cmd1.imageExtent = {8, 8, 1};
vkt::Buffer indirect_buffer1(*m_device, sizeof(cmd1), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
vkt::Buffer indirect_buffer2(*m_device, sizeof(cmd1) * 2,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address);
const VkDeviceAddress address1 = indirect_buffer1.Address();
const VkDeviceAddress address2 = indirect_buffer2.Address();
if (address1 == address2) {
GTEST_SKIP() << "Device addresses areequal.";
}
m_command_buffer.Begin();
vkt::Image dst_image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT);
VkStridedDeviceAddressRangeKHR address_range = {};
address_range.address = address1;
address_range.size = sizeof(cmd1);
address_range.stride = sizeof(VkCopyMemoryToImageIndirectCommandKHR);
VkImageSubresourceLayers res_layer = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkCopyMemoryToImageIndirectInfoKHR copy_info = vku::InitStructHelper();
copy_info.copyCount = 1;
copy_info.copyAddressRange = address_range;
copy_info.srcCopyFlags = VK_ADDRESS_COPY_DEVICE_LOCAL_BIT_KHR;
copy_info.dstImage = dst_image;
copy_info.dstImageLayout = VK_IMAGE_LAYOUT_GENERAL;
copy_info.pImageSubresources = &res_layer;
vk::CmdCopyMemoryToImageIndirectKHR(m_command_buffer, &copy_info);
copy_info.copyAddressRange.address = address2;
vk::CmdCopyMemoryToImageIndirectKHR(m_command_buffer, &copy_info);
indirect_buffer1.Destroy();
indirect_buffer2.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkEndCommandBuffer-commandBuffer-00059");
vk::EndCommandBuffer(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, BindResourceHeap) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::descriptorHeap);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props);
GetPhysicalDeviceProperties2(props2);
const VkDeviceSize resource_stride = std::max(heap_props.resourceHeapAlignment, heap_props.imageDescriptorAlignment);
const VkDeviceSize heap_size =
Align(Align(resource_stride + heap_props.minResourceHeapReservedRange, heap_props.bufferDescriptorAlignment),
heap_props.imageDescriptorAlignment);
VkBufferUsageFlags2CreateInfo buffer_usage = vku::InitStructHelper();
buffer_usage.usage = VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer resource_heap(*m_device, vkt::Buffer::CreateInfo(heap_size, 0, {}, &buffer_usage),
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &allocate_flag_info);
VkBindHeapInfoEXT bind_info = vku::InitStructHelper();
bind_info.heapRange = resource_heap.AddressRange();
bind_info.reservedRangeOffset = 0;
bind_info.reservedRangeSize = heap_props.minResourceHeapReservedRange;
m_command_buffer.Begin();
vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_info);
m_command_buffer.End();
resource_heap.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, BindSamplerHeap) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::descriptorHeap);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props);
GetPhysicalDeviceProperties2(props2);
const VkDeviceSize sampler_stride = std::max(heap_props.samplerHeapAlignment, heap_props.samplerDescriptorAlignment);
const VkDeviceSize heap_size =
Align(sampler_stride + heap_props.minSamplerHeapReservedRange, heap_props.samplerDescriptorAlignment);
VkBufferUsageFlags2CreateInfo buffer_usage = vku::InitStructHelper();
buffer_usage.usage = VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer sampler_heap(*m_device, vkt::Buffer::CreateInfo(heap_size, 0, {}, &buffer_usage),
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &allocate_flag_info);
VkBindHeapInfoEXT bind_info = vku::InitStructHelper();
bind_info.heapRange = sampler_heap.AddressRange();
bind_info.reservedRangeOffset = 0;
bind_info.reservedRangeSize = heap_props.minSamplerHeapReservedRange;
m_command_buffer.Begin();
vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_info);
m_command_buffer.End();
sampler_heap.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, PartialValidRange) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::descriptorHeap);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props);
GetPhysicalDeviceProperties2(props2);
const VkDeviceSize heap_size = heap_props.minSamplerHeapReservedRange + 256;
const VkDeviceSize offset = heap_size / 2;
VkBufferUsageFlags2CreateInfo buffer_usage = vku::InitStructHelper();
buffer_usage.usage = VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo buffer_ci = vku::InitStructHelper(&buffer_usage);
buffer_ci.size = heap_size;
vkt::Buffer heap1(*m_device, buffer_ci, vkt::no_mem);
buffer_ci.size = heap_size - offset;
vkt::Buffer heap2(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, heap1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
// make large enough if offset is not perfectly in the middle of the allocation
memory_ai.allocationSize = memory_requirements.size * 2;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, heap1, memory, 0);
vk::BindBufferMemory(*m_device, heap2, memory, offset);
VkDeviceAddress address1 = heap1.Address();
VkDeviceAddress address2 = heap2.Address();
(void)address2;
VkBindHeapInfoEXT bind_info = vku::InitStructHelper();
bind_info.heapRange = {address1, heap_size};
bind_info.reservedRangeOffset = 0;
bind_info.reservedRangeSize = heap_props.minSamplerHeapReservedRange;
m_command_buffer.Begin();
vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_info);
m_command_buffer.End();
heap1.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, ValidRangeTooSmall) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::descriptorHeap);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props);
GetPhysicalDeviceProperties2(props2);
const VkDeviceSize heap_size = heap_props.minSamplerHeapReservedRange + 256;
const VkDeviceSize offset = heap_size / 2;
VkBufferUsageFlags2CreateInfo buffer_usage = vku::InitStructHelper();
buffer_usage.usage = VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo buffer_ci = vku::InitStructHelper(&buffer_usage);
buffer_ci.size = heap_size;
vkt::Buffer heap1(*m_device, buffer_ci, vkt::no_mem);
buffer_ci.size = heap_size - offset;
vkt::Buffer heap2(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, heap1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
memory_ai.allocationSize = memory_requirements.size;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, heap1, memory, 0);
vk::BindBufferMemory(*m_device, heap2, memory, 0);
VkDeviceAddress address1 = heap1.Address();
VkDeviceAddress address2 = heap2.Address();
(void)address2;
VkBindHeapInfoEXT bind_info = vku::InitStructHelper();
bind_info.heapRange = {address1, heap_size};
bind_info.reservedRangeOffset = 0;
bind_info.reservedRangeSize = heap_props.minSamplerHeapReservedRange;
m_command_buffer.Begin();
vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_info);
m_command_buffer.End();
heap1.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, RangeSplitBetweenBuffers) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::descriptorHeap);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props);
GetPhysicalDeviceProperties2(props2);
const VkDeviceSize heap_size = heap_props.minSamplerHeapReservedRange + 256;
const VkDeviceSize offset = heap_size / 2;
VkBufferUsageFlags2CreateInfo buffer_usage = vku::InitStructHelper();
buffer_usage.usage = VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo buffer_ci = vku::InitStructHelper(&buffer_usage);
buffer_ci.size = heap_size;
vkt::Buffer heap1(*m_device, buffer_ci, vkt::no_mem);
buffer_ci.size = heap_size - offset;
vkt::Buffer heap2(*m_device, buffer_ci, vkt::no_mem);
vkt::Buffer heap3(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements;
vk::GetBufferMemoryRequirements(*m_device, heap1, &memory_requirements);
VkMemoryAllocateFlagsInfo memory_allocate_flags = vku::InitStructHelper();
memory_allocate_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkMemoryAllocateInfo memory_ai = vku::InitStructHelper(&memory_allocate_flags);
// make large enough if offset is not perfectly in the middle of the allocation
memory_ai.allocationSize = memory_requirements.size * 2;
bool pass =
m_device->Physical().SetMemoryType(memory_requirements.memoryTypeBits, &memory_ai, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
ASSERT_TRUE(pass);
vkt::DeviceMemory memory(*m_device, memory_ai);
vk::BindBufferMemory(*m_device, heap1, memory, 0);
vk::BindBufferMemory(*m_device, heap2, memory, 0);
vk::BindBufferMemory(*m_device, heap3, memory, offset);
VkDeviceAddress address1 = heap1.Address();
VkDeviceAddress address2 = heap2.Address();
VkDeviceAddress address3 = heap2.Address();
(void)address2;
(void)address3;
VkBindHeapInfoEXT bind_info = vku::InitStructHelper();
bind_info.heapRange = {address1, heap_size};
bind_info.reservedRangeOffset = 0;
bind_info.reservedRangeSize = heap_props.minSamplerHeapReservedRange;
m_command_buffer.Begin();
vk::CmdBindSamplerHeapEXT(m_command_buffer, &bind_info);
m_command_buffer.End();
heap1.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, IndexBuffer) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, 256u, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, vkt::device_address);
VkBindIndexBuffer3InfoKHR info = vku::InitStructHelper();
info.addressRange = buffer.AddressRange();
info.addressFlags = 0u;
info.indexType = VK_INDEX_TYPE_UINT32;
m_command_buffer.Begin();
vk::CmdBindIndexBuffer3KHR(m_command_buffer, &info);
m_command_buffer.End();
buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, CmdDrawIndirect2KHR) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
vkt::Buffer buffer(*m_device, sizeof(VkDrawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
VkDrawIndirectCommand* draw_ptr = static_cast<VkDrawIndirectCommand*>(buffer.Memory().Map());
draw_ptr->vertexCount = 3u;
draw_ptr->instanceCount = 1u;
draw_ptr->firstVertex = 0u;
draw_ptr->firstInstance = 0u;
VkDrawIndirect2InfoKHR info = vku::InitStructHelper();
info.addressRange = buffer.StridedAddressRange(sizeof(VkDrawIndirectCommand));
info.addressFlags = 0u;
info.drawCount = 1u;
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDrawIndirect2KHR(m_command_buffer, &info);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, CmdFillMemoryUsage) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, 256u, VK_BUFFER_USAGE_TRANSFER_DST_BIT, vkt::device_address);
VkDeviceAddressRangeKHR range;
range.address = buffer.Address();
range.size = 256u;
const uint32_t data = 255;
VkAddressCommandFlagsKHR flags = 0u;
m_command_buffer.Begin();
vk::CmdFillMemoryKHR(m_command_buffer, &range, flags, data);
m_command_buffer.End();
buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, ConditionalRendering) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::conditionalRendering);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
RETURN_IF_SKIP(Init());
vkt::Buffer buffer(*m_device, 256u, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT, vkt::device_address);
VkConditionalRenderingBeginInfo2EXT info = vku::InitStructHelper();
info.addressRange = buffer.AddressRange();
info.addressFlags = 0u;
info.flags = 0u;
m_command_buffer.Begin();
vk::CmdBeginConditionalRendering2EXT(m_command_buffer, &info);
vk::CmdEndConditionalRenderingEXT(m_command_buffer);
m_command_buffer.End();
buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDeviceAddress, TransformFeedback) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
AddRequiredFeature(vkt::Feature::transformFeedback);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
vkt::Buffer buffer(
*m_device, 256u,
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT,
vkt::device_address);
VkBindTransformFeedbackBuffer2InfoEXT info = vku::InitStructHelper();
info.addressRange = buffer.AddressRange();
info.addressFlags = VK_ADDRESS_COMMAND_TRANSFORM_FEEDBACK_BUFFER_USAGE_BIT_KHR;
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindTransformFeedbackBuffers2EXT(m_command_buffer, 0u, 1u, &info);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
buffer.Destroy();
m_errorMonitor->SetDesiredError("VUID-vkQueueSubmit-pCommandBuffers-00070");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}