| /* |
| * Copyright (c) 2015-2024 The Khronos Group Inc. |
| * Copyright (c) 2015-2024 Valve Corporation |
| * Copyright (c) 2015-2024 LunarG, Inc. |
| * Copyright (c) 2015-2024 Google, Inc. |
| * Modifications Copyright (C) 2020 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 "utils/vk_layer_utils.h" |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/external_memory_sync.h" |
| |
| class NegativeSparseImage : public VkLayerTest {}; |
| |
| TEST_F(NegativeSparseImage, BindingImageBufferCreate) { |
| TEST_DESCRIPTION("Create buffer/image with sparse attributes but without the sparse_binding bit set"); |
| AddRequiredFeature(vkt::Feature::sparseResidencyAliased); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| |
| VkBufferCreateInfo buf_info = vku::InitStructHelper(); |
| buf_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
| buf_info.size = 2048; |
| |
| if (m_device->Physical().Features().sparseResidencyBuffer) { |
| buf_info.flags = VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT; |
| CreateBufferTest(*this, &buf_info, "VUID-VkBufferCreateInfo-flags-00918"); |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyBuffer feature"; |
| } |
| |
| if (m_device->Physical().Features().sparseResidencyAliased) { |
| buf_info.flags = VK_BUFFER_CREATE_SPARSE_ALIASED_BIT; |
| CreateBufferTest(*this, &buf_info, "VUID-VkBufferCreateInfo-flags-00918"); |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyAliased feature"; |
| } |
| |
| 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.width = 512; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| if (m_device->Physical().Features().sparseResidencyImage2D) { |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-flags-00987"); |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyImage2D feature"; |
| } |
| |
| if (m_device->Physical().Features().sparseResidencyAliased) { |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_ALIASED_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-flags-00987"); |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyAliased feature"; |
| } |
| } |
| |
| TEST_F(NegativeSparseImage, ResidencyImageCreateUnsupportedTypes) { |
| TEST_DESCRIPTION("Create images with sparse residency with unsupported types"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.imageType = VK_IMAGE_TYPE_1D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 512; |
| image_create_info.extent.height = 1; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| |
| // 1D image w/ sparse residency is an error |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00970"); |
| |
| // 2D image w/ sparse residency when feature isn't available |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.extent.height = 64; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00971"); |
| |
| // 3D image w/ sparse residency when feature isn't available |
| image_create_info.imageType = VK_IMAGE_TYPE_3D; |
| image_create_info.extent.depth = 8; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00972"); |
| } |
| |
| TEST_F(NegativeSparseImage, ResidencyImageCreateUnsupportedSamples) { |
| TEST_DESCRIPTION("Create images with sparse residency with unsupported tiling or sample counts"); |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| 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.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_LINEAR; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| |
| // 2D image w/ sparse residency and linear tiling is an error |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-tiling-04121"); |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| |
| // Multi-sample image w/ sparse residency when feature isn't available (4 flavors) |
| image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00973"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_4_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00974"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_8_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00975"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_16_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00976"); |
| } |
| |
| TEST_F(NegativeSparseImage, ResidencyFlag) { |
| TEST_DESCRIPTION("Try to use VkSparseImageMemoryBindInfo without sparse residency flag"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 512; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| VkSparseImageMemoryBind image_memory_bind = {}; |
| image_memory_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_memory_bind.extent = image_create_info.extent; |
| |
| VkSparseImageMemoryBindInfo image_memory_bind_info = {}; |
| image_memory_bind_info.image = image.handle(); |
| image_memory_bind_info.bindCount = 1; |
| image_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.imageBindCount = 1; |
| bind_info.pImageBinds = &image_memory_bind_info; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBindInfo-image-02901"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSparseImage, ImageUsageBits) { |
| TEST_DESCRIPTION("Try to use VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT with sparse image"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| RETURN_IF_SKIP(Init()); |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| 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 = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-None-01925"); |
| } |
| |
| TEST_F(NegativeSparseImage, MemoryBindOffset) { |
| TEST_DESCRIPTION("Try to use VkSparseImageMemoryBind with offset not less than memory size"); |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); |
| buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
| buffer_create_info.size = 0x10000; |
| |
| if (m_device->Physical().Features().sparseResidencyBuffer) { |
| buffer_create_info.flags = VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyBuffer feature"; |
| } |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(nullptr); |
| image_create_info.flags = 0; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 8; |
| image_create_info.extent.height = 8; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| if (m_device->Physical().Features().sparseResidencyImage2D) { |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| } else { |
| GTEST_SKIP() << "Test requires unsupported sparseResidencyImage2D feature"; |
| } |
| |
| vkt::Buffer buffer(*m_device, buffer_create_info, vkt::no_mem); |
| VkMemoryRequirements buffer_mem_reqs; |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| VkMemoryAllocateInfo buffer_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, buffer_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| buffer_mem_alloc.allocationSize = |
| (buffer_mem_alloc.allocationSize + buffer_mem_reqs.alignment - 1) & ~(buffer_mem_reqs.alignment - 1); |
| vkt::DeviceMemory buffer_mem(*m_device, buffer_mem_alloc); |
| |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| VkMemoryAllocateInfo image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| image_mem_alloc.allocationSize = |
| (image_mem_alloc.allocationSize + image_mem_reqs.alignment - 1) & ~(image_mem_reqs.alignment - 1); |
| vkt::DeviceMemory image_mem(*m_device, image_mem_alloc); |
| |
| VkSparseMemoryBind buffer_memory_bind = {}; |
| buffer_memory_bind.size = buffer_create_info.size; |
| buffer_memory_bind.memory = buffer_mem; |
| buffer_memory_bind.memoryOffset = buffer_mem_alloc.allocationSize; |
| |
| VkSparseImageMemoryBind image_memory_bind = {}; |
| image_memory_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_memory_bind.memoryOffset = image_mem_alloc.allocationSize; |
| image_memory_bind.memory = image_mem; |
| image_memory_bind.extent = image_create_info.extent; |
| |
| VkSparseBufferMemoryBindInfo buffer_memory_bind_info = {}; |
| buffer_memory_bind_info.buffer = buffer; |
| buffer_memory_bind_info.bindCount = 1; |
| buffer_memory_bind_info.pBinds = &buffer_memory_bind; |
| |
| VkSparseMemoryBind image_opaque_memory_bind = {}; |
| image_opaque_memory_bind.size = 4 * image_create_info.extent.width * image_create_info.extent.height; |
| image_opaque_memory_bind.memory = image_mem; |
| image_opaque_memory_bind.memoryOffset = image_mem_alloc.allocationSize; |
| |
| VkSparseImageOpaqueMemoryBindInfo image_opaque_memory_bind_info = {}; |
| image_opaque_memory_bind_info.image = image; |
| image_opaque_memory_bind_info.bindCount = 1; |
| image_opaque_memory_bind_info.pBinds = &image_opaque_memory_bind; |
| |
| VkSparseImageMemoryBindInfo image_memory_bind_info = {}; |
| image_memory_bind_info.image = image; |
| image_memory_bind_info.bindCount = 1; |
| image_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.bufferBindCount = 1; |
| bind_info.pBufferBinds = &buffer_memory_bind_info; |
| bind_info.imageOpaqueBindCount = 1; |
| bind_info.pImageOpaqueBinds = &image_opaque_memory_bind_info; |
| bind_info.imageBindCount = 1; |
| bind_info.pImageBinds = &image_memory_bind_info; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memoryOffset-01101", 3); |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-size-01102", 2); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSparseImage, QueueBindSparseMemoryType) { |
| TEST_DESCRIPTION("Test QueueBindSparse with memory of a wrong type"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| const uint32_t mem_types_mask = (1u << m_device->Physical().memory_properties_.memoryTypeCount) - 1; |
| |
| /// Create buffer whose memory has an incompatible type |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); |
| buffer_create_info.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| buffer_create_info.size = 1024; |
| |
| vkt::Buffer buffer(*m_device, buffer_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements buffer_mem_reqs; |
| vk::GetBufferMemoryRequirements(device(), buffer.handle(), &buffer_mem_reqs); |
| const bool buffer_supports_all_mem_types = (buffer_mem_reqs.memoryTypeBits & mem_types_mask) == mem_types_mask; |
| VkMemoryAllocateInfo buffer_mem_alloc = vku::InitStructHelper(); |
| buffer_mem_alloc.allocationSize = buffer_mem_reqs.size; |
| buffer_mem_alloc.memoryTypeIndex = vvl::kU32Max; |
| // Try to pick incompatible memory type |
| for (uint32_t memory_type_i = 0; memory_type_i < m_device->Physical().memory_properties_.memoryTypeCount; ++memory_type_i) { |
| if (m_device->Physical().memory_properties_.memoryTypes[memory_type_i].propertyFlags & |
| VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD) { |
| continue; |
| } |
| |
| if (m_device->Physical().memory_properties_.memoryTypes[memory_type_i].propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) { |
| continue; |
| } |
| |
| if (!((1u << memory_type_i) & buffer_mem_reqs.memoryTypeBits)) { |
| buffer_mem_alloc.memoryTypeIndex = memory_type_i; |
| break; |
| } |
| } |
| |
| if (buffer_mem_alloc.memoryTypeIndex == vvl::kU32Max) { |
| GTEST_SKIP() << "Could not find suitable memory type for buffer, skipping test"; |
| } |
| |
| const bool buffer_mem_lazy = |
| m_device->Physical().memory_properties_.memoryTypes[buffer_mem_alloc.memoryTypeIndex].propertyFlags & |
| VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; |
| |
| vkt::DeviceMemory buffer_mem(*m_device, buffer_mem_alloc); |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| /// Create image whose memory has an incompatible type |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(device(), image.handle(), &image_mem_reqs); |
| const bool image_supports_all_mem_types = (image_mem_reqs.memoryTypeBits & mem_types_mask) == mem_types_mask; |
| VkMemoryAllocateInfo image_mem_alloc = vku::InitStructHelper(); |
| image_mem_alloc.allocationSize = image_mem_reqs.size; |
| image_mem_alloc.memoryTypeIndex = vvl::kU32Max; |
| // Try to pick incompatible memory type |
| for (uint32_t memory_type_i = 0; memory_type_i < m_device->Physical().memory_properties_.memoryTypeCount; ++memory_type_i) { |
| if (m_device->Physical().memory_properties_.memoryTypes[memory_type_i].propertyFlags & |
| VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD) { |
| continue; |
| } |
| |
| if (m_device->Physical().memory_properties_.memoryTypes[memory_type_i].propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) { |
| continue; |
| } |
| |
| if (!((1u << memory_type_i) & image_mem_reqs.memoryTypeBits)) { |
| image_mem_alloc.memoryTypeIndex = memory_type_i; |
| break; |
| } |
| } |
| |
| if (image_mem_alloc.memoryTypeIndex == vvl::kU32Max) { |
| GTEST_SKIP() << "Could not find suitable memory type for image, skipping test"; |
| } |
| |
| const bool image_mem_lazy = m_device->Physical().memory_properties_.memoryTypes[image_mem_alloc.memoryTypeIndex].propertyFlags & |
| VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; |
| |
| vkt::DeviceMemory image_mem(*m_device, image_mem_alloc); |
| |
| /// Specify memory bindings |
| VkSparseMemoryBind buffer_memory_bind = {}; |
| buffer_memory_bind.size = buffer_mem_reqs.size; |
| buffer_memory_bind.memory = buffer_mem.handle(); |
| |
| VkSparseMemoryBind image_memory_bind = {}; |
| image_memory_bind.size = image_mem_reqs.size; |
| image_memory_bind.memory = image_mem.handle(); |
| |
| VkSparseBufferMemoryBindInfo buffer_memory_bind_info = {}; |
| buffer_memory_bind_info.buffer = buffer.handle(); |
| buffer_memory_bind_info.bindCount = 1; |
| buffer_memory_bind_info.pBinds = &buffer_memory_bind; |
| |
| VkSparseImageOpaqueMemoryBindInfo image_opaque_memory_bind_info = {}; |
| image_opaque_memory_bind_info.image = image.handle(); |
| image_opaque_memory_bind_info.bindCount = 1; |
| image_opaque_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.pBufferBinds = &buffer_memory_bind_info; |
| bind_info.pImageOpaqueBinds = &image_opaque_memory_bind_info; |
| |
| // Validate only buffer |
| if (!buffer_supports_all_mem_types) { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| if (buffer_mem_lazy) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } else { |
| printf("Could not find an invalid memory type for buffer, skipping part of test.\n"); |
| } |
| |
| // Validate only image |
| if (!image_supports_all_mem_types) { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| if (image_mem_lazy) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } else { |
| printf("Could not find an invalid memory type for image, skipping part of test.\n"); |
| } |
| |
| // Validate both a buffer and image error occur |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 1; |
| if (!buffer_supports_all_mem_types) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| if (buffer_mem_lazy) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| } |
| if (!image_supports_all_mem_types) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| if (image_mem_lazy) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeSparseImage, QueueBindSparseMemoryType2) { |
| TEST_DESCRIPTION("Test QueueBindSparse with lazily allocated memory"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| uint32_t lazily_allocated_index = |
| m_device->Physical().memory_properties_.memoryTypeCount; // Set to an invalid value just in case |
| for (uint32_t i = 0; i < m_device->Physical().memory_properties_.memoryTypeCount; ++i) { |
| if ((m_device->Physical().memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0) { |
| lazily_allocated_index = i; |
| break; |
| } |
| } |
| if (lazily_allocated_index == m_device->Physical().memory_properties_.memoryTypeCount) { |
| GTEST_SKIP() << "Did not find memory with VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT"; |
| } |
| |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); |
| buffer_create_info.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| buffer_create_info.size = 1024; |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| vkt::Buffer buffer(*m_device, buffer_create_info, vkt::no_mem); |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements buffer_mem_reqs; |
| vk::GetBufferMemoryRequirements(device(), buffer.handle(), &buffer_mem_reqs); |
| VkMemoryAllocateInfo buffer_mem_alloc = vku::InitStructHelper(); |
| buffer_mem_alloc.allocationSize = buffer_mem_reqs.size; |
| buffer_mem_alloc.memoryTypeIndex = lazily_allocated_index; |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(device(), image.handle(), &image_mem_reqs); |
| VkMemoryAllocateInfo image_mem_alloc = vku::InitStructHelper(); |
| image_mem_alloc.allocationSize = image_mem_reqs.size; |
| image_mem_alloc.memoryTypeIndex = lazily_allocated_index; |
| |
| vkt::DeviceMemory buffer_mem(*m_device, buffer_mem_alloc); |
| |
| vkt::DeviceMemory image_mem(*m_device, image_mem_alloc); |
| |
| VkSparseMemoryBind buffer_memory_bind = {}; |
| buffer_memory_bind.size = buffer_mem_reqs.size; |
| buffer_memory_bind.memory = buffer_mem.handle(); |
| |
| VkSparseMemoryBind image_memory_bind = {}; |
| image_memory_bind.size = image_mem_reqs.size; |
| image_memory_bind.memory = image_mem.handle(); |
| |
| VkSparseBufferMemoryBindInfo buffer_memory_bind_info = {}; |
| buffer_memory_bind_info.buffer = buffer.handle(); |
| buffer_memory_bind_info.bindCount = 1; |
| buffer_memory_bind_info.pBinds = &buffer_memory_bind; |
| |
| VkSparseImageOpaqueMemoryBindInfo image_opaque_memory_bind_info = {}; |
| image_opaque_memory_bind_info.image = image.handle(); |
| image_opaque_memory_bind_info.bindCount = 1; |
| image_opaque_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.pBufferBinds = &buffer_memory_bind_info; |
| bind_info.pImageOpaqueBinds = &image_opaque_memory_bind_info; |
| |
| // Validate only buffer |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| if (!((1u << buffer_mem_alloc.memoryTypeIndex) & buffer_mem_reqs.memoryTypeBits)) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate only image |
| { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| if (!((1u << image_mem_alloc.memoryTypeIndex) & image_mem_reqs.memoryTypeBits)) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate both a buffer and image error occur |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01097"); |
| if (!((1u << buffer_mem_alloc.memoryTypeIndex) & buffer_mem_reqs.memoryTypeBits)) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| if (!((1u << image_mem_alloc.memoryTypeIndex) & image_mem_reqs.memoryTypeBits)) { |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| } |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeSparseImage, QueueBindSparseMemoryType3) { |
| TEST_DESCRIPTION( |
| "Test QueueBindSparse with memory having export external handle types that do not match those of the resource"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| IgnoreHandleTypeError(m_errorMonitor); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| /// Allocate buffer and buffer memory with an external handle type |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); // Do not set any supported external handle type |
| buffer_create_info.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| buffer_create_info.size = 1024; |
| vkt::Buffer buffer(*m_device, buffer_create_info, vkt::no_mem); |
| const auto buffer_exportable_types = |
| FindSupportedExternalMemoryHandleTypes(Gpu(), buffer_create_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT); |
| if (!buffer_exportable_types) { |
| GTEST_SKIP() << "Unable to find exportable handle type for buffer, skipping test"; |
| } |
| const auto buffer_exportable_type = LeastSignificantFlag<VkExternalMemoryHandleTypeFlagBits>(buffer_exportable_types); |
| VkExportMemoryAllocateInfo buffer_export_mem_alloc_info = vku::InitStructHelper(); |
| buffer_export_mem_alloc_info.handleTypes = GetCompatibleHandleTypes(Gpu(), buffer_create_info, buffer_exportable_type); |
| VkMemoryRequirements buffer_mem_reqs{}; |
| vk::GetBufferMemoryRequirements(device(), buffer.handle(), &buffer_mem_reqs); |
| const VkMemoryAllocateInfo buffer_mem_alloc = vkt::DeviceMemory::GetResourceAllocInfo( |
| *m_device, buffer_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &buffer_export_mem_alloc_info); |
| vkt::DeviceMemory buffer_mem(*m_device, buffer_mem_alloc); |
| |
| /// Allocate image and image memory with an external handle type |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); // Do not set any supported external handle type |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| const auto image_exportable_types = |
| FindSupportedExternalMemoryHandleTypes(Gpu(), image_create_info, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT); |
| if (!image_exportable_types) { |
| GTEST_SKIP() << "Unable to find exportable handle type for image, skipping test"; |
| } |
| const auto image_exportable_type = LeastSignificantFlag<VkExternalMemoryHandleTypeFlagBits>(image_exportable_types); |
| |
| VkExportMemoryAllocateInfo image_export_mem_alloc_info = vku::InitStructHelper(); |
| image_export_mem_alloc_info.handleTypes = GetCompatibleHandleTypes(Gpu(), image_create_info, image_exportable_type); |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(device(), image.handle(), &image_mem_reqs); |
| const VkMemoryAllocateInfo image_mem_alloc = vkt::DeviceMemory::GetResourceAllocInfo( |
| *m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image_export_mem_alloc_info); |
| vkt::DeviceMemory image_mem(*m_device, image_mem_alloc); |
| |
| // Setup memory bindings |
| VkSparseMemoryBind buffer_memory_bind = {}; |
| buffer_memory_bind.size = buffer_mem_reqs.size; |
| buffer_memory_bind.memory = buffer_mem.handle(); |
| |
| VkSparseBufferMemoryBindInfo buffer_memory_bind_info = {}; |
| buffer_memory_bind_info.buffer = buffer.handle(); |
| buffer_memory_bind_info.bindCount = 1; |
| buffer_memory_bind_info.pBinds = &buffer_memory_bind; |
| |
| VkSparseMemoryBind image_memory_bind = {}; |
| image_memory_bind.size = image_mem_reqs.size; |
| image_memory_bind.memory = image_mem.handle(); |
| |
| VkSparseImageOpaqueMemoryBindInfo image_opaque_memory_bind_info = {}; |
| image_opaque_memory_bind_info.image = image.handle(); |
| image_opaque_memory_bind_info.bindCount = 1; |
| image_opaque_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkSparseImageMemoryBind image_memory_bind_2 = {}; |
| image_memory_bind_2.extent = image_create_info.extent; |
| image_memory_bind_2.memory = image_mem.handle(); |
| image_memory_bind_2.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| VkSparseImageMemoryBindInfo image_memory_bind_info = {}; |
| image_memory_bind_info.image = image; |
| image_memory_bind_info.bindCount = 1; |
| image_memory_bind_info.pBinds = &image_memory_bind_2; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.pBufferBinds = &buffer_memory_bind_info; |
| bind_info.pImageOpaqueBinds = &image_opaque_memory_bind_info; |
| bind_info.pImageBinds = &image_memory_bind_info; |
| |
| // Validate only buffer |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02730"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate only image opaque bind |
| { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02730"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate both a buffer and image error occur |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02730", 2); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate only image bind |
| { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 0; |
| bind_info.imageBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-memory-02732"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeSparseImage, QueueBindSparseMemoryType4) { |
| TEST_DESCRIPTION( |
| "Test QueueBindSparse with memory having import external handle types that do not match those of the resource"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| #ifdef _WIN32 |
| const auto ext_mem_extension_name = VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; |
| #else |
| const auto ext_mem_extension_name = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME; |
| const auto handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; |
| #endif |
| |
| AddRequiredExtensions(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); |
| AddRequiredExtensions(ext_mem_extension_name); |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyBuffer); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage2D); |
| RETURN_IF_SKIP(Init()); |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "External tests are not supported by MockICD, skipping tests"; |
| } |
| |
| // Check for import/export capability |
| VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info = { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR, nullptr, VK_BUFFER_CREATE_SPARSE_BINDING_BIT, |
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, handle_type}; |
| VkExternalBufferProperties external_buffer_props = {VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR, nullptr, {0, 0, 0}}; |
| vk::GetPhysicalDeviceExternalBufferProperties(Gpu(), &external_buffer_info, &external_buffer_props); |
| if (!(external_buffer_props.externalMemoryProperties.compatibleHandleTypes & handle_type) || |
| !(external_buffer_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) || |
| !(external_buffer_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) { |
| GTEST_SKIP() << "External buffer does not support importing and exporting"; |
| } |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| // Check if dedicated allocation is required |
| const bool dedicated_allocation = |
| external_buffer_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT; |
| if (dedicated_allocation) { |
| // VUID-VkMemoryDedicatedAllocateInfo-buffer-01436 |
| GTEST_SKIP() << "Dedicated allocation is required, which cannot be used with VK_BUFFER_CREATE_SPARSE_BINDING_BIT"; |
| } |
| |
| /// Allocate buffer and buffer memory with no supported external type |
| VkExternalMemoryBufferCreateInfo external_memory_buffer_info = vku::InitStructHelper(); |
| external_memory_buffer_info.handleTypes = 0; |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(&external_memory_buffer_info); |
| buffer_create_info.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| buffer_create_info.size = 1024; |
| vkt::Buffer buffer1(*m_device, buffer_create_info, vkt::no_mem); |
| buffer_create_info.size = 65536; |
| vkt::Buffer buffer2(*m_device, buffer_create_info, vkt::no_mem); |
| |
| VkMemoryAllocateInfo buffer_mem_alloc1 = vkt::DeviceMemory::GetResourceAllocInfo(*m_device, buffer1.MemoryRequirements(), 0); |
| VkMemoryAllocateInfo buffer_mem_alloc2 = vkt::DeviceMemory::GetResourceAllocInfo(*m_device, buffer2.MemoryRequirements(), 0); |
| VkExportMemoryAllocateInfo export_info1 = vku::InitStructHelper(); |
| export_info1.handleTypes = handle_type; |
| buffer_mem_alloc1.pNext = &export_info1; |
| VkExportMemoryAllocateInfo export_info2 = vku::InitStructHelper(); |
| export_info2.handleTypes = handle_type; |
| buffer_mem_alloc2.pNext = &export_info2; |
| |
| // Export memory |
| vkt::DeviceMemory buffer_memory_export1(*m_device, buffer_mem_alloc1); |
| vkt::DeviceMemory buffer_memory_export2(*m_device, buffer_mem_alloc2); |
| |
| #ifdef _WIN32 |
| // Export memory to handle |
| VkMemoryGetWin32HandleInfoKHR mghi = vku::InitStructHelper(); |
| mghi.memory = buffer_memory_export1; |
| mghi.handleType = handle_type; |
| |
| HANDLE handle1; |
| ASSERT_EQ(VK_SUCCESS, vk::GetMemoryWin32HandleKHR(device(), &mghi, &handle1)); |
| |
| VkImportMemoryWin32HandleInfoKHR import_info1 = vku::InitStructHelper(); |
| import_info1.handleType = handle_type; |
| import_info1.handle = handle1; |
| |
| mghi.memory = buffer_memory_export2; |
| HANDLE handle2; |
| ASSERT_EQ(VK_SUCCESS, vk::GetMemoryWin32HandleKHR(device(), &mghi, &handle2)); |
| |
| VkImportMemoryWin32HandleInfoKHR import_info2 = vku::InitStructHelper(); |
| import_info2.handleType = handle_type; |
| import_info2.handle = handle2; |
| #else |
| // Export memory to fd |
| VkMemoryGetFdInfoKHR mgfi = vku::InitStructHelper(); |
| mgfi.memory = buffer_memory_export1; |
| mgfi.handleType = handle_type; |
| |
| int fd1 = 0; |
| ASSERT_EQ(VK_SUCCESS, vk::GetMemoryFdKHR(device(), &mgfi, &fd1)); |
| |
| VkImportMemoryFdInfoKHR import_info1 = vku::InitStructHelper(); |
| import_info1.handleType = handle_type; |
| import_info1.fd = fd1; |
| |
| mgfi.memory = buffer_memory_export2; |
| int fd2 = 0; |
| ASSERT_EQ(VK_SUCCESS, vk::GetMemoryFdKHR(device(), &mgfi, &fd2)); |
| |
| VkImportMemoryFdInfoKHR import_info2 = vku::InitStructHelper(); |
| import_info2.handleType = handle_type; |
| import_info2.fd = fd2; |
| #endif |
| |
| buffer_mem_alloc1.pNext = &import_info1; |
| vkt::DeviceMemory buffer_memory_imported(*m_device, buffer_mem_alloc1); |
| |
| /// Allocate image and image memory with an external handle type |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); // Do not set any supported external handle type |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(device(), image.handle(), &image_mem_reqs); |
| const VkMemoryAllocateInfo image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &import_info2); |
| vkt::DeviceMemory image_mem(*m_device, image_mem_alloc); |
| |
| // Setup memory bindings |
| VkSparseMemoryBind buffer_memory_bind = {}; |
| buffer_memory_bind.size = buffer1.MemoryRequirements().size; |
| buffer_memory_bind.memory = buffer_memory_imported.handle(); |
| |
| VkSparseBufferMemoryBindInfo buffer_memory_bind_info = {}; |
| buffer_memory_bind_info.buffer = buffer1.handle(); |
| buffer_memory_bind_info.bindCount = 1; |
| buffer_memory_bind_info.pBinds = &buffer_memory_bind; |
| |
| VkSparseMemoryBind image_memory_bind = {}; |
| image_memory_bind.size = image_mem_reqs.size; |
| image_memory_bind.memory = image_mem.handle(); |
| |
| VkSparseImageOpaqueMemoryBindInfo image_opaque_memory_bind_info = {}; |
| image_opaque_memory_bind_info.image = image.handle(); |
| image_opaque_memory_bind_info.bindCount = 1; |
| image_opaque_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkSparseImageMemoryBind image_memory_bind_2 = {}; |
| image_memory_bind_2.extent = image_create_info.extent; |
| image_memory_bind_2.memory = image_mem.handle(); |
| image_memory_bind_2.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| VkSparseImageMemoryBindInfo image_memory_bind_info = {}; |
| image_memory_bind_info.image = image; |
| image_memory_bind_info.bindCount = 1; |
| image_memory_bind_info.pBinds = &image_memory_bind_2; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.pBufferBinds = &buffer_memory_bind_info; |
| bind_info.pImageOpaqueBinds = &image_opaque_memory_bind_info; |
| bind_info.pImageBinds = &image_memory_bind_info; |
| |
| // Validate only buffer |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02731"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate only image opaque bind |
| { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02731"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate both a buffer and image error occur |
| { |
| bind_info.bufferBindCount = 1; |
| bind_info.imageOpaqueBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-02731", 2); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Validate only image bind |
| { |
| bind_info.bufferBindCount = 0; |
| bind_info.imageOpaqueBindCount = 0; |
| bind_info.imageBindCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-memory-02733"); |
| vk::QueueBindSparse(m_device->QueuesWithSparseCapability()[0]->handle(), 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeSparseImage, ImageMemoryBind) { |
| TEST_DESCRIPTION("Try to bind sparse resident image with invalid VkSparseImageMemoryBind"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage3D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkImageCreateInfo create_info = vkt::Image::CreateInfo(); |
| create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| create_info.imageType = VK_IMAGE_TYPE_3D; |
| create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| create_info.extent.width = 1024; |
| create_info.extent.height = 1024; |
| create_info.extent.depth = 1; |
| create_info.arrayLayers = 1; |
| vkt::Image image(*m_device, create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), image.handle(), &image_mem_reqs); |
| const auto image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| vkt::DeviceMemory image_mem; |
| image_mem.init(*m_device, image_mem_alloc); |
| |
| uint32_t requirements_count = 0u; |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, nullptr); |
| |
| if (requirements_count == 0u) { |
| GTEST_SKIP() << "No sparse image requirements for image format VK_FORMAT_B8G8R8A8_UNORM"; |
| } |
| |
| std::vector<VkSparseImageMemoryRequirements> sparse_reqs(requirements_count); |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, sparse_reqs.data()); |
| |
| VkExtent3D granularity = sparse_reqs[0].formatProperties.imageGranularity; |
| VkSparseImageMemoryBind image_bind{}; |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_bind.memory = image_mem.handle(); |
| image_bind.extent = granularity; |
| |
| VkSparseImageMemoryBindInfo image_bind_info{}; |
| image_bind_info.image = image.handle(); |
| image_bind_info.bindCount = 1u; |
| image_bind_info.pBinds = &image_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.imageBindCount = 1u; |
| bind_info.pImageBinds = &image_bind_info; |
| |
| VkQueue sparse_queue = m_device->QueuesWithSparseCapability()[0]->handle(); |
| |
| // Force offset.x to invalid value |
| image_bind.offset.x = granularity.width - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-offset-01107"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.offset.x = 0u; |
| |
| // Force offset.y to invalid value |
| image_bind.offset.y = granularity.height - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-offset-01109"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.offset.y = 0u; |
| |
| // Force offset.y to invalid value |
| image_bind.offset.z = granularity.depth - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-offset-01111"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.offset.z = 0u; |
| |
| // Force extent.width to invalid value |
| image_bind.extent.width = granularity.width - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-01108"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.extent.width = granularity.width; |
| |
| // Force extent.height to invalid value |
| image_bind.extent.height = granularity.height - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-01110"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.extent.height = granularity.height; |
| |
| // Force extent.depth to invalid value |
| image_bind.extent.depth = granularity.depth - 1; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-01112"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.extent.depth = granularity.depth; |
| |
| // Force greater mip level |
| image_bind.subresource.mipLevel = VK_REMAINING_MIP_LEVELS; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBindInfo-subresource-01722"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.subresource.mipLevel = 0; |
| |
| // Force greater array layer |
| image_bind.subresource.arrayLayer = VK_REMAINING_ARRAY_LAYERS; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBindInfo-subresource-01723"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.subresource.arrayLayer = 0; |
| |
| // Force invalid aspect mask |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBindInfo-subresource-01106"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| } |
| |
| TEST_F(NegativeSparseImage, ImageMemoryBindInvalidMemory) { |
| TEST_DESCRIPTION("Try to bind sparse resident image with invalid VkSparseImageMemoryBind"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage3D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkImageCreateInfo create_info = vkt::Image::CreateInfo(); |
| create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| create_info.imageType = VK_IMAGE_TYPE_3D; |
| create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| create_info.extent.width = 1024; |
| create_info.extent.height = 1024; |
| create_info.extent.depth = 1; |
| create_info.arrayLayers = 1; |
| vkt::Image image(*m_device, create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), image.handle(), &image_mem_reqs); |
| const auto image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| vkt::DeviceMemory image_mem; |
| image_mem.init(*m_device, image_mem_alloc); |
| |
| VkImageCreateInfo invalid_create_info = create_info; |
| vkt::Image invalid_image(*m_device, invalid_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements invalid_image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), invalid_image.handle(), &invalid_image_mem_reqs); |
| |
| // Make sure that the same memory type is not chosen. |
| invalid_image_mem_reqs.memoryTypeBits = ~image_mem_reqs.memoryTypeBits; |
| |
| VkMemoryAllocateInfo invalid_image_mem_alloc = vku::InitStructHelper(); |
| invalid_image_mem_alloc.allocationSize = invalid_image_mem_reqs.size; |
| if (!m_device->Physical().SetMemoryType(invalid_image_mem_reqs.memoryTypeBits, &invalid_image_mem_alloc, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_PROTECTED_BIT)) { |
| GTEST_SKIP() << "Could not find required memory type"; |
| } |
| |
| vkt::DeviceMemory invalid_image_mem; |
| invalid_image_mem.init(*m_device, invalid_image_mem_alloc); |
| |
| uint32_t requirements_count = 0u; |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, nullptr); |
| |
| if (requirements_count == 0u) { |
| GTEST_SKIP() << "No sparse image requirements for image format VK_FORMAT_B8G8R8A8_UNORM"; |
| } |
| |
| std::vector<VkSparseImageMemoryRequirements> sparse_reqs(requirements_count); |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, sparse_reqs.data()); |
| |
| VkExtent3D granularity = sparse_reqs[0].formatProperties.imageGranularity; |
| VkSparseImageMemoryBind image_bind{}; |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_bind.memory = image_mem.handle(); |
| image_bind.memoryOffset = 0; |
| image_bind.extent = granularity; |
| |
| VkSparseImageMemoryBindInfo image_bind_info{}; |
| image_bind_info.image = image.handle(); |
| image_bind_info.bindCount = 1u; |
| image_bind_info.pBinds = &image_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.imageBindCount = 1u; |
| bind_info.pImageBinds = &image_bind_info; |
| |
| VkQueue sparse_queue = m_device->QueuesWithSparseCapability()[0]->handle(); |
| |
| // Force invalid device memory |
| image_bind.memory = invalid_image_mem.handle(); |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-memory-01105"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSparseImage, ImageMemoryBindInvalidAlignment) { |
| TEST_DESCRIPTION("Try to bind sparse resident image with invalid VkSparseImageMemoryBind"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage3D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkImageCreateInfo create_info = vkt::Image::CreateInfo(); |
| create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| create_info.imageType = VK_IMAGE_TYPE_3D; |
| create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| create_info.extent.width = 1024; |
| create_info.extent.height = 1024; |
| create_info.extent.depth = 1; |
| create_info.arrayLayers = 1; |
| vkt::Image image(*m_device, create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), image.handle(), &image_mem_reqs); |
| if (image_mem_reqs.alignment == 1) { |
| GTEST_SKIP() << "Need image memory required alignment to be more than 1"; |
| } |
| |
| const auto image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| vkt::DeviceMemory image_mem; |
| image_mem.init(*m_device, image_mem_alloc); |
| |
| VkImageCreateInfo invalid_create_info = create_info; |
| vkt::Image invalid_image(*m_device, invalid_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements invalid_image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), invalid_image.handle(), &invalid_image_mem_reqs); |
| |
| // Make sure that the same memory type is not chosen. |
| invalid_image_mem_reqs.memoryTypeBits = ~image_mem_reqs.memoryTypeBits; |
| |
| VkMemoryAllocateInfo invalid_image_mem_alloc = vku::InitStructHelper(); |
| invalid_image_mem_alloc.allocationSize = invalid_image_mem_reqs.size; |
| if (!m_device->Physical().SetMemoryType(invalid_image_mem_reqs.memoryTypeBits, &invalid_image_mem_alloc, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_PROTECTED_BIT)) { |
| GTEST_SKIP() << "Could not find required memory type"; |
| } |
| |
| vkt::DeviceMemory invalid_image_mem; |
| invalid_image_mem.init(*m_device, invalid_image_mem_alloc); |
| |
| uint32_t requirements_count = 0u; |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, nullptr); |
| |
| if (requirements_count == 0u) { |
| GTEST_SKIP() << "No sparse image requirements for image format VK_FORMAT_B8G8R8A8_UNORM"; |
| } |
| |
| std::vector<VkSparseImageMemoryRequirements> sparse_reqs(requirements_count); |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, sparse_reqs.data()); |
| |
| VkExtent3D granularity = sparse_reqs[0].formatProperties.imageGranularity; |
| VkSparseImageMemoryBind image_bind{}; |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_bind.memory = image_mem.handle(); |
| image_bind.memoryOffset = 0; |
| image_bind.extent = granularity; |
| |
| VkSparseImageMemoryBindInfo image_bind_info{}; |
| image_bind_info.image = image.handle(); |
| image_bind_info.bindCount = 1u; |
| image_bind_info.pBinds = &image_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.imageBindCount = 1u; |
| bind_info.pImageBinds = &image_bind_info; |
| |
| VkQueue sparse_queue = m_device->QueuesWithSparseCapability()[0]->handle(); |
| |
| // Force memoryOffset to invalid value |
| image_bind.memoryOffset = image_mem_reqs.alignment + 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-memory-01105"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| image_bind.memoryOffset = 0; |
| } |
| |
| TEST_F(NegativeSparseImage, ImageMemoryBindInvalidExtent) { |
| TEST_DESCRIPTION("Try to bind sparse resident image with an extent having a null size on one of its dimension"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| AddRequiredFeature(vkt::Feature::sparseResidencyImage3D); |
| RETURN_IF_SKIP(Init()); |
| |
| if (m_device->QueuesWithSparseCapability().empty()) { |
| GTEST_SKIP() << "Required SPARSE_BINDING queue families not present"; |
| } |
| |
| VkImageCreateInfo create_info = vkt::Image::CreateInfo(); |
| create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| create_info.imageType = VK_IMAGE_TYPE_3D; |
| create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| create_info.extent.width = 1024; |
| create_info.extent.height = 1024; |
| create_info.extent.depth = 1; |
| create_info.arrayLayers = 1; |
| vkt::Image image(*m_device, create_info, vkt::no_mem); |
| |
| VkMemoryRequirements image_mem_reqs; |
| vk::GetImageMemoryRequirements(m_device->handle(), image.handle(), &image_mem_reqs); |
| const auto image_mem_alloc = |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image_mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| vkt::DeviceMemory image_mem; |
| image_mem.init(*m_device, image_mem_alloc); |
| |
| uint32_t requirements_count = 0u; |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, nullptr); |
| |
| if (requirements_count == 0u) { |
| GTEST_SKIP() << "No sparse image requirements for image format VK_FORMAT_B8G8R8A8_UNORM"; |
| } |
| |
| std::vector<VkSparseImageMemoryRequirements> sparse_reqs(requirements_count); |
| vk::GetImageSparseMemoryRequirements(m_device->handle(), image.handle(), &requirements_count, sparse_reqs.data()); |
| |
| VkExtent3D granularity = sparse_reqs[0].formatProperties.imageGranularity; |
| VkSparseImageMemoryBind image_bind{}; |
| image_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_bind.memory = image_mem.handle(); |
| image_bind.extent = granularity; |
| |
| VkSparseImageMemoryBindInfo image_bind_info{}; |
| image_bind_info.image = image.handle(); |
| image_bind_info.bindCount = 1u; |
| image_bind_info.pBinds = &image_bind; |
| |
| VkBindSparseInfo bind_info = vku::InitStructHelper(); |
| bind_info.imageBindCount = 1u; |
| bind_info.pImageBinds = &image_bind_info; |
| |
| VkQueue sparse_queue = m_device->QueuesWithSparseCapability()[0]->handle(); |
| |
| image_bind.extent.width = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-09388"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| image_bind.extent = granularity; |
| |
| image_bind.extent.height = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-09389"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| image_bind.extent = granularity; |
| |
| image_bind.extent.depth = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkSparseImageMemoryBind-extent-09390"); |
| vk::QueueBindSparse(sparse_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSparseImage, UnalignedBindOffsets) { |
| TEST_DESCRIPTION("VkSparseMemoryBind have unaligned memory offset and resource offset"); |
| |
| AddRequiredFeature(vkt::Feature::sparseBinding); |
| RETURN_IF_SKIP(Init()); |
| |
| auto index = m_device->graphics_queue_node_index_; |
| if (!(m_device->Physical().queue_properties_[index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) { |
| GTEST_SKIP() << "Graphics queue does not have sparse binding bit"; |
| } |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_create_info.extent.width = 1024; |
| image_create_info.extent.height = 1024; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| 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.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| vkt::Image image(*m_device, image_create_info, vkt::no_mem); |
| |
| VkMemoryRequirements memory_reqs; |
| vk::GetImageMemoryRequirements(device(), image, &memory_reqs); |
| if (memory_reqs.alignment == 1) { |
| GTEST_SKIP() << "Need image memory required alignment to be more than 1"; |
| } |
| // Find an image big enough to allow sparse mapping of 2 memory regions |
| // Increase the image size until it is at least twice the |
| // size of the required alignment, to ensure we can bind both |
| // allocated memory blocks to the image on aligned offsets. |
| while (memory_reqs.size < (memory_reqs.alignment * 2)) { |
| image.destroy(); |
| image_create_info.extent.width *= 2; |
| image_create_info.extent.height *= 2; |
| image.InitNoMemory(*m_device, image_create_info); |
| vk::GetImageMemoryRequirements(device(), image, &memory_reqs); |
| } |
| // Allocate 2 memory regions of minimum alignment size, bind one at 0, the other |
| // at the end of the first |
| VkMemoryAllocateInfo memory_info = vku::InitStructHelper(); |
| memory_info.allocationSize = 2 * memory_reqs.alignment; |
| bool pass = m_device->Physical().SetMemoryType(memory_reqs.memoryTypeBits, &memory_info, 0); |
| ASSERT_TRUE(pass); |
| vkt::DeviceMemory memory_one(*m_device, memory_info); |
| vkt::DeviceMemory memory_two(*m_device, memory_info); |
| |
| std::array<VkSparseMemoryBind, 2> binds = {}; |
| binds[0].memory = memory_one; |
| binds[0].memoryOffset = 1; |
| binds[0].resourceOffset = memory_info.allocationSize / 2; |
| binds[0].size = memory_info.allocationSize / 2; |
| binds[1].memory = memory_two; |
| binds[1].memoryOffset = 0; |
| binds[1].resourceOffset = 1; |
| binds[1].size = memory_info.allocationSize / 2; |
| |
| VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo; |
| opaqueBindInfo.image = image; |
| opaqueBindInfo.bindCount = size32(binds); |
| opaqueBindInfo.pBinds = binds.data(); |
| |
| VkBindSparseInfo bindSparseInfo = vku::InitStructHelper(); |
| bindSparseInfo.imageOpaqueBindCount = 1; |
| bindSparseInfo.pImageOpaqueBinds = &opaqueBindInfo; |
| |
| // Unaligned memory bind offset |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-memory-01096"); |
| // Unaligned memory bind offset, and resource offset |
| m_errorMonitor->SetDesiredError("VUID-VkSparseMemoryBind-resourceOffset-09492", 2); |
| vk::QueueBindSparse(m_default_queue->handle(), 1, &bindSparseInfo, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| // Wait for operations to finish before destroying anything |
| m_default_queue->Wait(); |
| } |