| /* |
| * 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, ©_region); |
| vk::CmdCopyMemoryToImageIndirectKHR(m_command_buffer, ©_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, ©_info); |
| |
| copy_info.copyAddressRange.address = address2; |
| vk::CmdCopyMemoryToImageIndirectKHR(m_command_buffer, ©_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(); |
| } |