From c79a528d2b58dfa6f3d856271cbf29697a5322a1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tapani=20P=C3=A4lli?= Date: Thu, 8 Nov 2018 10:20:35 +0200 Subject: [PATCH] anv/android: support import/export of AHardwareBuffer objects MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit v2: add support for non-image buffers (AHARDWAREBUFFER_FORMAT_BLOB) v3: properly handle usage bits when creating from image v4: refactor, code cleanup (Jason) v5: rebase to b43f955037c changes, initialize bo flags as ANV_BO_EXTERNAL (Lionel) v6: add assert that anv_bo_cache_import succeeds, add comment about multi-bo support to clarify current implementation (Lionel) Signed-off-by: Tapani Pälli Reviewed-by: Lionel Landwerlin --- src/intel/vulkan/anv_android.c | 127 +++++++++++++++++++++++++++ src/intel/vulkan/anv_android.h | 10 +++ src/intel/vulkan/anv_android_stubs.c | 16 ++++ src/intel/vulkan/anv_device.c | 45 +++++++++- src/intel/vulkan/anv_private.h | 5 ++ 5 files changed, 201 insertions(+), 2 deletions(-) diff --git a/src/intel/vulkan/anv_android.c b/src/intel/vulkan/anv_android.c index 7b7e214379f..ca1eae7be99 100644 --- a/src/intel/vulkan/anv_android.c +++ b/src/intel/vulkan/anv_android.c @@ -246,6 +246,133 @@ anv_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create, return ahw_usage; } +VkResult +anv_GetMemoryAndroidHardwareBufferANDROID( + VkDevice device_h, + const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo, + struct AHardwareBuffer **pBuffer) +{ + ANV_FROM_HANDLE(anv_device_memory, mem, pInfo->memory); + + /* Some quotes from Vulkan spec: + * + * "If the device memory was created by importing an Android hardware + * buffer, vkGetMemoryAndroidHardwareBufferANDROID must return that same + * Android hardware buffer object." + * + * "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must + * have been included in VkExportMemoryAllocateInfoKHR::handleTypes when + * memory was created." + */ + if (mem->ahw) { + *pBuffer = mem->ahw; + /* Increase refcount. */ + AHardwareBuffer_acquire(mem->ahw); + return VK_SUCCESS; + } + + return VK_ERROR_OUT_OF_HOST_MEMORY; +} + +/* + * Called from anv_AllocateMemory when import AHardwareBuffer. + */ +VkResult +anv_import_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkImportAndroidHardwareBufferInfoANDROID *info) +{ + ANV_FROM_HANDLE(anv_device, device, device_h); + + /* Import from AHardwareBuffer to anv_device_memory. */ + const native_handle_t *handle = + AHardwareBuffer_getNativeHandle(info->buffer); + + /* NOTE - We support buffers with only one handle but do not error on + * multiple handle case. Reason is that we want to support YUV formats + * where we have many logical planes but they all point to the same + * buffer, like is the case with VK_FORMAT_G8_B8R8_2PLANE_420_UNORM. + */ + int dma_buf = (handle && handle->numFds) ? handle->data[0] : -1; + if (dma_buf < 0) + return VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR; + + uint64_t bo_flags = ANV_BO_EXTERNAL; + if (device->instance->physicalDevice.supports_48bit_addresses) + bo_flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS; + if (device->instance->physicalDevice.use_softpin) + bo_flags |= EXEC_OBJECT_PINNED; + + VkResult result = anv_bo_cache_import(device, &device->bo_cache, + dma_buf, bo_flags, &mem->bo); + assert(VK_SUCCESS); + + /* "If the vkAllocateMemory command succeeds, the implementation must + * acquire a reference to the imported hardware buffer, which it must + * release when the device memory object is freed. If the command fails, + * the implementation must not retain a reference." + */ + AHardwareBuffer_acquire(info->buffer); + mem->ahw = info->buffer; + + return VK_SUCCESS; +} + +VkResult +anv_create_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkMemoryAllocateInfo *pAllocateInfo) +{ + ANV_FROM_HANDLE(anv_device, dev, device_h); + + const VkMemoryDedicatedAllocateInfo *dedicated_info = + vk_find_struct_const(pAllocateInfo->pNext, + MEMORY_DEDICATED_ALLOCATE_INFO); + + uint32_t w = 0; + uint32_t h = 1; + uint32_t layers = 1; + uint32_t format = 0; + uint64_t usage = 0; + + /* If caller passed dedicated information. */ + if (dedicated_info && dedicated_info->image) { + ANV_FROM_HANDLE(anv_image, image, dedicated_info->image); + w = image->extent.width; + h = image->extent.height; + layers = image->array_size; + format = android_format_from_vk(image->vk_format); + usage = anv_ahw_usage_from_vk_usage(image->create_flags, image->usage); + } else if (dedicated_info && dedicated_info->buffer) { + ANV_FROM_HANDLE(anv_buffer, buffer, dedicated_info->buffer); + w = buffer->size; + format = AHARDWAREBUFFER_FORMAT_BLOB; + usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + } else { + w = pAllocateInfo->allocationSize; + format = AHARDWAREBUFFER_FORMAT_BLOB; + usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + } + + struct AHardwareBuffer *ahw = NULL; + struct AHardwareBuffer_Desc desc = { + .width = w, + .height = h, + .layers = layers, + .format = format, + .usage = usage, + }; + + if (AHardwareBuffer_allocate(&desc, &ahw) != 0) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + mem->ahw = ahw; + + return VK_SUCCESS; +} + VkResult anv_image_from_gralloc(VkDevice device_h, const VkImageCreateInfo *base_info, diff --git a/src/intel/vulkan/anv_android.h b/src/intel/vulkan/anv_android.h index 8d748cecc39..01f0e856291 100644 --- a/src/intel/vulkan/anv_android.h +++ b/src/intel/vulkan/anv_android.h @@ -28,6 +28,8 @@ #include #include +struct anv_device_memory; + VkResult anv_image_from_gralloc(VkDevice device_h, const VkImageCreateInfo *base_info, const VkNativeBufferANDROID *gralloc_info, @@ -36,4 +38,12 @@ VkResult anv_image_from_gralloc(VkDevice device_h, uint64_t anv_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create, const VkImageUsageFlags vk_usage); + +VkResult anv_import_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkImportAndroidHardwareBufferInfoANDROID *info); + +VkResult anv_create_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkMemoryAllocateInfo *pAllocateInfo); #endif /* ANV_ANDROID_H */ diff --git a/src/intel/vulkan/anv_android_stubs.c b/src/intel/vulkan/anv_android_stubs.c index 0671d5635ee..ccc16500494 100644 --- a/src/intel/vulkan/anv_android_stubs.c +++ b/src/intel/vulkan/anv_android_stubs.c @@ -39,3 +39,19 @@ anv_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create, { return 0; } + +VkResult +anv_import_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkImportAndroidHardwareBufferInfoANDROID *info) +{ + return VK_ERROR_EXTENSION_NOT_PRESENT; +} + +VkResult +anv_create_ahw_memory(VkDevice device_h, + struct anv_device_memory *mem, + const VkMemoryAllocateInfo *pAllocateInfo) +{ + return VK_ERROR_EXTENSION_NOT_PRESENT; +} diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index fb824d3ca43..fa3a8a417b9 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -2268,6 +2268,7 @@ VkResult anv_AllocateMemory( mem->type = &pdevice->memory.types[pAllocateInfo->memoryTypeIndex]; mem->map = NULL; mem->map_size = 0; + mem->ahw = NULL; uint64_t bo_flags = 0; @@ -2290,6 +2291,43 @@ VkResult anv_AllocateMemory( if (pdevice->use_softpin) bo_flags |= EXEC_OBJECT_PINNED; + const VkExportMemoryAllocateInfo *export_info = + vk_find_struct_const(pAllocateInfo->pNext, EXPORT_MEMORY_ALLOCATE_INFO); + + /* Check if we need to support Android HW buffer export. If so, + * create AHardwareBuffer and import memory from it. + */ + bool android_export = false; + if (export_info && export_info->handleTypes & + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) + android_export = true; + + /* Android memory import. */ + const struct VkImportAndroidHardwareBufferInfoANDROID *ahw_import_info = + vk_find_struct_const(pAllocateInfo->pNext, + IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID); + + if (ahw_import_info) { + result = anv_import_ahw_memory(_device, mem, ahw_import_info); + if (result != VK_SUCCESS) + goto fail; + + goto success; + } else if (android_export) { + result = anv_create_ahw_memory(_device, mem, pAllocateInfo); + if (result != VK_SUCCESS) + goto fail; + + const struct VkImportAndroidHardwareBufferInfoANDROID import_info = { + .buffer = mem->ahw, + }; + result = anv_import_ahw_memory(_device, mem, &import_info); + if (result != VK_SUCCESS) + goto fail; + + goto success; + } + const VkImportMemoryFdInfoKHR *fd_info = vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FD_INFO_KHR); @@ -2345,8 +2383,6 @@ VkResult anv_AllocateMemory( /* Regular allocate (not importing memory). */ - const VkExportMemoryAllocateInfoKHR *export_info = - vk_find_struct_const(pAllocateInfo->pNext, EXPORT_MEMORY_ALLOCATE_INFO_KHR); if (export_info && export_info->handleTypes) bo_flags |= ANV_BO_EXTERNAL; @@ -2450,6 +2486,11 @@ void anv_FreeMemory( anv_bo_cache_release(device, &device->bo_cache, mem->bo); +#ifdef ANDROID + if (mem->ahw) + AHardwareBuffer_release(mem->ahw); +#endif + vk_free2(&device->alloc, pAllocator, mem); } diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 4a7ea3c3565..bfd1482ef8d 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1399,6 +1399,11 @@ struct anv_device_memory { struct anv_memory_type * type; VkDeviceSize map_size; void * map; + + /* If set, we are holding reference to AHardwareBuffer + * which we must release when memory is freed. + */ + struct AHardwareBuffer * ahw; }; /** -- 2.30.2