From b261d73cdc2b7749d8237937f22d21a6b3a4fb59 Mon Sep 17 00:00:00 2001 From: sfricke-samsung Date: Wed, 8 Jul 2020 20:54:24 -0700 Subject: [PATCH 1/4] layers: Remove AHB bindBuffer VUs From internal Vulkan MR 3982, the VUID 4003 and 4005 should not have been added to start with and more information about it was added to the spec as well. --- layers/core_validation.cpp | 55 +++++++++++++++++--------------------- layers/state_tracker.cpp | 5 +--- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index 6efaad21019..4c653ac83df 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -3699,41 +3699,36 @@ bool CoreChecks::ValidateBindBufferMemory(VkBuffer buffer, VkDeviceMemory mem, V const auto mem_info = GetDevMemState(mem); - // All validation using the buffer_state->requirements for external AHB is check in android only section - if (buffer_state->external_ahb == false) { - // Validate memory requirements alignment - if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) { - const char *vuid = bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memoryOffset-01600" - : "VUID-vkBindBufferMemory-memoryOffset-01036"; - skip |= LogError(buffer, vuid, - "%s: memoryOffset is 0x%" PRIxLEAST64 - " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64 - ", returned from a call to vkGetBufferMemoryRequirements with buffer.", - api_name, memoryOffset, buffer_state->requirements.alignment); - } + // Validate memory requirements alignment + if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) { + const char *vuid = + bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memoryOffset-01600" : "VUID-vkBindBufferMemory-memoryOffset-01036"; + skip |= LogError(buffer, vuid, + "%s: memoryOffset is 0x%" PRIxLEAST64 + " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64 + ", returned from a call to vkGetBufferMemoryRequirements with buffer.", + api_name, memoryOffset, buffer_state->requirements.alignment); + } - if (mem_info) { - // Validate bound memory range information - skip |= ValidateInsertBufferMemoryRange(buffer, mem_info, memoryOffset, api_name); + if (mem_info) { + // Validate bound memory range information + skip |= ValidateInsertBufferMemoryRange(buffer, mem_info, memoryOffset, api_name); - const char *mem_type_vuid = - bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memory-01599" : "VUID-vkBindBufferMemory-memory-01035"; - skip |= ValidateMemoryTypes(mem_info, buffer_state->requirements.memoryTypeBits, api_name, mem_type_vuid); + const char *mem_type_vuid = + bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memory-01599" : "VUID-vkBindBufferMemory-memory-01035"; + skip |= ValidateMemoryTypes(mem_info, buffer_state->requirements.memoryTypeBits, api_name, mem_type_vuid); - // Validate memory requirements size - if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) { - const char *vuid = - bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-size-01601" : "VUID-vkBindBufferMemory-size-01037"; - skip |= LogError(buffer, vuid, - "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64 - " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64 - ", returned from a call to vkGetBufferMemoryRequirements with buffer.", - api_name, mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size); - } + // Validate memory requirements size + if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) { + const char *vuid = + bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-size-01601" : "VUID-vkBindBufferMemory-size-01037"; + skip |= LogError(buffer, vuid, + "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64 + " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64 + ", returned from a call to vkGetBufferMemoryRequirements with buffer.", + api_name, mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size); } - } - if (mem_info) { // Validate dedicated allocation if (mem_info->is_dedicated && ((mem_info->dedicated_buffer != buffer) || (memoryOffset != 0))) { const char *vuid = diff --git a/layers/state_tracker.cpp b/layers/state_tracker.cpp index 2db16425850..1a8ba24302a 100644 --- a/layers/state_tracker.cpp +++ b/layers/state_tracker.cpp @@ -429,10 +429,7 @@ void ValidationStateTracker::PostCallRecordCreateBuffer(VkDevice device, const V RecordCreateBufferANDROID(pCreateInfo, buffer_state.get()); } // Get a set of requirements in the case the app does not - // External AHB memory can't be queried until after memory is bound - if (buffer_state->external_ahb == false) { - DispatchGetBufferMemoryRequirements(device, *pBuffer, &buffer_state->requirements); - } + DispatchGetBufferMemoryRequirements(device, *pBuffer, &buffer_state->requirements); buffer_state->unprotected = ((pCreateInfo->flags & VK_BUFFER_CREATE_PROTECTED_BIT) == 0); From fd9b9f22961d09769f21f4fbb5f3a6fb95eb819e Mon Sep 17 00:00:00 2001 From: sfricke-samsung Date: Tue, 21 Jul 2020 23:26:39 -0700 Subject: [PATCH 2/4] tests: AHB test for bindBufferMemory --- tests/vklayertests_others.cpp | 94 ++++++++++++++++++++++++++++++ tests/vkpositivelayertests.cpp | 102 +++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/tests/vklayertests_others.cpp b/tests/vklayertests_others.cpp index 4f74bb9eda2..601a12aea4f 100644 --- a/tests/vklayertests_others.cpp +++ b/tests/vklayertests_others.cpp @@ -5622,6 +5622,100 @@ TEST_F(VkLayerTest, AndroidHardwareBufferExporttBuffer) { vk::DestroyImage(dev, img, NULL); } +TEST_F(VkLayerTest, AndroidHardwareBufferInvalidBindBufferMemory) { + TEST_DESCRIPTION("Validate binding AndroidHardwareBuffer VkBuffer act same as non-AHB buffers."); + + SetTargetApiVersion(VK_API_VERSION_1_1); + ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); + + if (IsPlatform(kGalaxyS10)) { + printf("%s This test should not run on Galaxy S10\n", kSkipPrefix); + return; + } + + if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && + // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension + (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { + m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + } else { + printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // Allocate an AHardwareBuffer + AHardwareBuffer *ahb; + AHardwareBuffer_Desc ahb_desc = {}; + ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB; + ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; + ahb_desc.width = 64; + ahb_desc.height = 1; + ahb_desc.layers = 1; + ahb_desc.stride = 1; + AHardwareBuffer_allocate(&ahb_desc, &ahb); + + VkExternalMemoryBufferCreateInfo ext_buf_info = {}; + ext_buf_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR; + ext_buf_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = &ext_buf_info; + buffer_create_info.size = 1 << 20; // 1 MB + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VkBuffer buffer = VK_NULL_HANDLE; + vk::CreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer); + + // Try to get memory requirements prior to binding memory + VkMemoryRequirements mem_reqs; + vk::GetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); + + VkImportAndroidHardwareBufferInfoANDROID import_ahb_Info = {}; + import_ahb_Info.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; + import_ahb_Info.pNext = nullptr; + import_ahb_Info.buffer = ahb; + + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = &import_ahb_Info; + memory_info.allocationSize = mem_reqs.size + mem_reqs.alignment; // save room for offset + bool has_memtype = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &memory_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!has_memtype) { + printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); + AHardwareBuffer_release(ahb); + vk::DestroyBuffer(m_device->device(), buffer, nullptr); + return; + } + + VkDeviceMemory memory; + vk::AllocateMemory(m_device->device(), &memory_info, NULL, &memory); + + if (mem_reqs.alignment > 1) { + m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01036"); + vk::BindBufferMemory(device(), buffer, memory, 1); + m_errorMonitor->VerifyFound(); + } + + VkDeviceSize buffer_offset = (mem_reqs.size - 1) & ~(mem_reqs.alignment - 1); + if (buffer_offset > 0) { + m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-size-01037"); + vk::BindBufferMemory(device(), buffer, memory, buffer_offset); + m_errorMonitor->VerifyFound(); + } + + vk::DestroyBuffer(m_device->device(), buffer, nullptr); + vk::FreeMemory(m_device->device(), memory, nullptr); +} + TEST_F(VkLayerTest, AndroidHardwareBufferImportBufferHandleType) { TEST_DESCRIPTION("Don't use proper resource handleType for import buffer"); diff --git a/tests/vkpositivelayertests.cpp b/tests/vkpositivelayertests.cpp index 30fca783852..1e27da0b241 100644 --- a/tests/vkpositivelayertests.cpp +++ b/tests/vkpositivelayertests.cpp @@ -9916,4 +9916,106 @@ TEST_F(VkPositiveLayerTest, AndroidHardwareBufferDepthStencil) { vk::FreeMemory(m_device->device(), memory, nullptr); } +TEST_F(VkPositiveLayerTest, AndroidHardwareBufferBindBufferMemory) { + TEST_DESCRIPTION("Verify AndroidHardwareBuffer Buffers can be queried for mem requirements while unbound."); + + SetTargetApiVersion(VK_API_VERSION_1_1); + ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); + + if (IsPlatform(kGalaxyS10)) { + printf("%s This test should not run on Galaxy S10\n", kSkipPrefix); + return; + } + + if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && + // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension + (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { + m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + } else { + printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps = + (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vk::GetDeviceProcAddr(m_device->device(), + "vkGetAndroidHardwareBufferPropertiesANDROID"); + ASSERT_TRUE(pfn_GetAHBProps != nullptr); + + // Allocate an AHardwareBuffer + AHardwareBuffer *ahb; + AHardwareBuffer_Desc ahb_desc = {}; + ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB; + ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; + ahb_desc.width = 64; + ahb_desc.height = 1; + ahb_desc.layers = 1; + ahb_desc.stride = 1; + AHardwareBuffer_allocate(&ahb_desc, &ahb); + + VkExternalMemoryBufferCreateInfo ext_buf_info = {}; + ext_buf_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR; + ext_buf_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = &ext_buf_info; + buffer_create_info.size = 8192; // greater than the 4k AHB usually are + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VkBuffer buffer = VK_NULL_HANDLE; + vk::CreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer); + + m_errorMonitor->ExpectSuccess(); + // Try to get memory requirements prior to binding memory + VkMemoryRequirements mem_reqs; + vk::GetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); + + // Test bind memory 2 extension + VkBufferMemoryRequirementsInfo2 buffer_mem_reqs2 = {}; + buffer_mem_reqs2.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2; + buffer_mem_reqs2.pNext = nullptr; + buffer_mem_reqs2.buffer = buffer; + VkMemoryRequirements2 mem_reqs2; + mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; + mem_reqs2.pNext = nullptr; + vk::GetBufferMemoryRequirements2(m_device->device(), &buffer_mem_reqs2, &mem_reqs2); + + VkImportAndroidHardwareBufferInfoANDROID import_ahb_Info = {}; + import_ahb_Info.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; + import_ahb_Info.pNext = nullptr; + import_ahb_Info.buffer = ahb; + + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = &import_ahb_Info; + memory_info.allocationSize = mem_reqs.size + mem_reqs.alignment; // save room for offset + bool has_memtype = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &memory_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!has_memtype) { + printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); + AHardwareBuffer_release(ahb); + vk::DestroyBuffer(m_device->device(), buffer, nullptr); + return; + } + + // Some drivers don't return exact size in getBufferMemory as getAHB + m_errorMonitor->SetUnexpectedError("VUID-VkMemoryAllocateInfo-allocationSize-02383"); + VkDeviceMemory memory; + vk::AllocateMemory(m_device->device(), &memory_info, NULL, &memory); + vk::BindBufferMemory(m_device->device(), buffer, memory, mem_reqs.alignment); + + m_errorMonitor->VerifyNotFound(); + + vk::DestroyBuffer(m_device->device(), buffer, nullptr); + vk::FreeMemory(m_device->device(), memory, nullptr); +} + #endif // VK_USE_PLATFORM_ANDROID_KHR From 9300a8075a83d853c27150b30fb9a776381fab50 Mon Sep 17 00:00:00 2001 From: sfricke-samsung Date: Tue, 21 Jul 2020 23:26:55 -0700 Subject: [PATCH 3/4] layers: Fix exported AHB checking allocationSize --- layers/core_validation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index 4c653ac83df..f364b73ed83 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -10408,7 +10408,11 @@ bool CoreChecks::ValidateBindImageMemory(uint32_t bindInfoCount, const VkBindIma if (mem_info) { // Validate bound memory range information - skip |= ValidateInsertImageMemoryRange(bindInfo.image, mem_info, bindInfo.memoryOffset, error_prefix); + // if memory is exported to an AHB then the mem_info->allocationSize must be zero and this check is not needed + if ((mem_info->is_export == false) || ((mem_info->export_handle_type_flags & + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) == 0)) { + skip |= ValidateInsertImageMemoryRange(bindInfo.image, mem_info, bindInfo.memoryOffset, error_prefix); + } // Validate dedicated allocation if (mem_info->is_dedicated) { From 7cf19a62c8a1813e0857693142ca4b68697bb141 Mon Sep 17 00:00:00 2001 From: sfricke-samsung Date: Tue, 21 Jul 2020 23:28:02 -0700 Subject: [PATCH 4/4] tests: Add export AHB positive tests --- tests/vklayertests_others.cpp | 13 ++- tests/vkpositivelayertests.cpp | 187 +++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 2 deletions(-) diff --git a/tests/vklayertests_others.cpp b/tests/vklayertests_others.cpp index 601a12aea4f..9b5f174c8ab 100644 --- a/tests/vklayertests_others.cpp +++ b/tests/vklayertests_others.cpp @@ -5230,6 +5230,11 @@ TEST_F(VkLayerTest, AndroidHardwareBufferCreateImageView) { SetTargetApiVersion(VK_API_VERSION_1_1); ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); + if (IsPlatform(kGalaxyS10)) { + printf("%s This test should not run on Galaxy S10\n", kSkipPrefix); + return; + } + if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { @@ -5696,8 +5701,12 @@ TEST_F(VkLayerTest, AndroidHardwareBufferInvalidBindBufferMemory) { return; } - VkDeviceMemory memory; - vk::AllocateMemory(m_device->device(), &memory_info, NULL, &memory); + VkDeviceMemory memory = VK_NULL_HANDLE; + VkResult result = vk::AllocateMemory(m_device->device(), &memory_info, NULL, &memory); + if ((memory == VK_NULL_HANDLE) || (result != VK_SUCCESS)) { + printf("%s This test failed to allocate memory for importing\n", kSkipPrefix); + return; + } if (mem_reqs.alignment > 1) { m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01036"); diff --git a/tests/vkpositivelayertests.cpp b/tests/vkpositivelayertests.cpp index 1e27da0b241..55ae79f67a1 100644 --- a/tests/vkpositivelayertests.cpp +++ b/tests/vkpositivelayertests.cpp @@ -10018,4 +10018,191 @@ TEST_F(VkPositiveLayerTest, AndroidHardwareBufferBindBufferMemory) { vk::FreeMemory(m_device->device(), memory, nullptr); } +TEST_F(VkPositiveLayerTest, AndroidHardwareBufferExportBuffer) { + TEST_DESCRIPTION("Verify VkBuffers can export to an AHB."); + + SetTargetApiVersion(VK_API_VERSION_1_1); + ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); + + if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && + // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension + (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { + m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + } else { + printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = + (PFN_vkGetMemoryAndroidHardwareBufferANDROID)vk::GetDeviceProcAddr(device(), "vkGetMemoryAndroidHardwareBufferANDROID"); + ASSERT_TRUE(vkGetMemoryAndroidHardwareBufferANDROID != nullptr); + + m_errorMonitor->ExpectSuccess(); + + // Create VkBuffer to be exported to an AHB + VkBuffer buffer = VK_NULL_HANDLE; + VkExternalMemoryBufferCreateInfo ext_buf_info = {}; + ext_buf_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR; + ext_buf_info.pNext = nullptr; + ext_buf_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = &ext_buf_info; + buffer_create_info.size = 4096; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vk::CreateBuffer(device(), &buffer_create_info, nullptr, &buffer); + + VkMemoryRequirements mem_reqs; + vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs); + + VkExportMemoryAllocateInfo export_memory_info = {}; + export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; + export_memory_info.pNext = nullptr; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = &export_memory_info; + memory_info.allocationSize = mem_reqs.size; + + bool has_memtype = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &memory_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!has_memtype) { + printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); + vk::DestroyBuffer(device(), buffer, nullptr); + return; + } + + VkDeviceMemory memory = VK_NULL_HANDLE; + ; + vk::AllocateMemory(device(), &memory_info, NULL, &memory); + vk::BindBufferMemory(device(), buffer, memory, 0); + + // Export memory to AHB + AHardwareBuffer *ahb = nullptr; + + VkMemoryGetAndroidHardwareBufferInfoANDROID get_ahb_info = {}; + get_ahb_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; + get_ahb_info.pNext = nullptr; + get_ahb_info.memory = memory; + vkGetMemoryAndroidHardwareBufferANDROID(device(), &get_ahb_info, &ahb); + + m_errorMonitor->VerifyNotFound(); + + // App in charge of releasing after exporting + AHardwareBuffer_release(ahb); + vk::FreeMemory(device(), memory, NULL); + vk::DestroyBuffer(device(), buffer, nullptr); +} + +TEST_F(VkPositiveLayerTest, AndroidHardwareBufferExportImage) { + TEST_DESCRIPTION("Verify VkImages can export to an AHB."); + + SetTargetApiVersion(VK_API_VERSION_1_1); + ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); + + if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) && + // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension + (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) { + m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + } else { + printf("%s %s extension not supported, skipping tests\n", kSkipPrefix, + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = + (PFN_vkGetMemoryAndroidHardwareBufferANDROID)vk::GetDeviceProcAddr(device(), "vkGetMemoryAndroidHardwareBufferANDROID"); + ASSERT_TRUE(vkGetMemoryAndroidHardwareBufferANDROID != nullptr); + + m_errorMonitor->ExpectSuccess(); + + // Create VkImage to be exported to an AHB + VkExternalMemoryImageCreateInfo ext_image_info = {}; + ext_image_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; + ext_image_info.pNext = nullptr; + ext_image_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkImage image = VK_NULL_HANDLE; + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = &ext_image_info; + 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 = {64, 1, 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.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + vk::CreateImage(device(), &image_create_info, nullptr, &image); + + VkMemoryDedicatedAllocateInfo memory_dedicated_info = {}; + memory_dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; + memory_dedicated_info.pNext = nullptr; + memory_dedicated_info.image = image; + memory_dedicated_info.buffer = VK_NULL_HANDLE; + + VkExportMemoryAllocateInfo export_memory_info = {}; + export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; + export_memory_info.pNext = &memory_dedicated_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = &export_memory_info; + + // "When allocating new memory for an image that can be exported to an Android hardware buffer, the memory’s allocationSize must + // be zero": + memory_info.allocationSize = 0; + + // Use any DEVICE_LOCAL memory found + bool has_memtype = m_device->phy().set_memory_type(0xFFFFFFFF, &memory_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!has_memtype) { + printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); + vk::DestroyImage(device(), image, nullptr); + return; + } + + VkDeviceMemory memory = VK_NULL_HANDLE; + vk::AllocateMemory(device(), &memory_info, NULL, &memory); + vk::BindImageMemory(device(), image, memory, 0); + + // Export memory to AHB + AHardwareBuffer *ahb = nullptr; + + VkMemoryGetAndroidHardwareBufferInfoANDROID get_ahb_info = {}; + get_ahb_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; + get_ahb_info.pNext = nullptr; + get_ahb_info.memory = memory; + vkGetMemoryAndroidHardwareBufferANDROID(device(), &get_ahb_info, &ahb); + + m_errorMonitor->VerifyNotFound(); + + // App in charge of releasing after exporting + AHardwareBuffer_release(ahb); + vk::FreeMemory(device(), memory, NULL); + vk::DestroyImage(device(), image, nullptr); +} + #endif // VK_USE_PLATFORM_ANDROID_KHR