From f36b52740a026c46f718a4cb63e70da0322d4b48 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Tue, 25 Jun 2019 11:42:03 +0200 Subject: [PATCH] radv/android: Add android hardware buffer queries. Derived from the Intel code. For the internal format we just use the internal Vulkan format, as we have Vulkan formats for all android formats we care about. For the ycbcr properties we just do something. I do not have a real clue what would be recommended. Reviewed-by: Samuel Pitoiset --- src/amd/vulkan/meson.build | 1 + src/amd/vulkan/radv_android.c | 181 ++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build index afc5bde56c7..7fa945a346f 100644 --- a/src/amd/vulkan/meson.build +++ b/src/amd/vulkan/meson.build @@ -139,6 +139,7 @@ if with_xlib_lease endif if with_platform_android + radv_deps += dep_android radv_flags += [ '-DVK_USE_PLATFORM_ANDROID_KHR' ] diff --git a/src/amd/vulkan/radv_android.c b/src/amd/vulkan/radv_android.c index ba4716801e7..df4812257e6 100644 --- a/src/amd/vulkan/radv_android.c +++ b/src/amd/vulkan/radv_android.c @@ -24,11 +24,13 @@ #include #include #include +#include #include #include #include #include "radv_private.h" +#include "vk_util.h" static int radv_hal_open(const struct hw_module_t* mod, const char* id, struct hw_device_t** dev); static int radv_hal_close(struct hw_device_t *dev); @@ -372,3 +374,182 @@ radv_QueueSignalReleaseImageANDROID( } return VK_SUCCESS; } + +#if RADV_SUPPORT_ANDROID_HARDWARE_BUFFER + +enum { + /* Usage bit equal to GRALLOC_USAGE_HW_CAMERA_MASK */ + AHARDWAREBUFFER_USAGE_CAMERA_MASK = 0x00060000U, +}; + +static inline VkFormat +vk_format_from_android(unsigned android_format, unsigned android_usage) +{ + switch (android_format) { + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + return VK_FORMAT_R8G8B8A8_UNORM; + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + return VK_FORMAT_R8G8B8_UNORM; + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: + return VK_FORMAT_R5G6B5_UNORM_PACK16; + case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: + return VK_FORMAT_R16G16B16A16_SFLOAT; + case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: + return VK_FORMAT_A2B10G10R10_UNORM_PACK32; + case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: + return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; + case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: + if (android_usage & AHARDWAREBUFFER_USAGE_CAMERA_MASK) + return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; + else + return VK_FORMAT_R8G8B8_UNORM; + case AHARDWAREBUFFER_FORMAT_BLOB: + default: + return VK_FORMAT_UNDEFINED; + } +} + +static VkResult +get_ahb_buffer_format_properties( + VkDevice device_h, + const struct AHardwareBuffer *buffer, + VkAndroidHardwareBufferFormatPropertiesANDROID *pProperties) +{ + RADV_FROM_HANDLE(radv_device, device, device_h); + + /* Get a description of buffer contents . */ + AHardwareBuffer_Desc desc; + AHardwareBuffer_describe(buffer, &desc); + + /* Verify description. */ + const uint64_t gpu_usage = + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | + AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; + + /* "Buffer must be a valid Android hardware buffer object with at least + * one of the AHARDWAREBUFFER_USAGE_GPU_* usage flags." + */ + if (!(desc.usage & (gpu_usage))) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + + /* Fill properties fields based on description. */ + VkAndroidHardwareBufferFormatPropertiesANDROID *p = pProperties; + + p->format = vk_format_from_android(desc.format, desc.usage); + p->externalFormat = (uint64_t) (uintptr_t) p->format; + + VkFormatProperties format_properties; + radv_GetPhysicalDeviceFormatProperties( + radv_physical_device_to_handle(device->physical_device), + p->format, &format_properties); + + if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) + p->formatFeatures = format_properties.linearTilingFeatures; + else + p->formatFeatures = format_properties.optimalTilingFeatures; + + /* "Images can be created with an external format even if the Android hardware + * buffer has a format which has an equivalent Vulkan format to enable + * consistent handling of images from sources that might use either category + * of format. However, all images created with an external format are subject + * to the valid usage requirements associated with external formats, even if + * the Android hardware buffer’s format has a Vulkan equivalent." + * + * "The formatFeatures member *must* include + * VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT and at least one of + * VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or + * VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT" + */ + assert(p->formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); + + p->formatFeatures |= VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; + + /* "Implementations may not always be able to determine the color model, + * numerical range, or chroma offsets of the image contents, so the values + * in VkAndroidHardwareBufferFormatPropertiesANDROID are only suggestions. + * Applications should treat these values as sensible defaults to use in + * the absence of more reliable information obtained through some other + * means." + */ + p->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY; + p->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY; + p->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY; + p->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY; + + p->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601; + p->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; + + p->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; + p->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; + + return VK_SUCCESS; +} + +VkResult +radv_GetAndroidHardwareBufferPropertiesANDROID( + VkDevice device_h, + const struct AHardwareBuffer *buffer, + VkAndroidHardwareBufferPropertiesANDROID *pProperties) +{ + RADV_FROM_HANDLE(radv_device, dev, device_h); + struct radv_physical_device *pdevice = dev->physical_device; + + VkAndroidHardwareBufferFormatPropertiesANDROID *format_prop = + vk_find_struct(pProperties->pNext, + ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID); + + /* Fill format properties of an Android hardware buffer. */ + if (format_prop) + get_ahb_buffer_format_properties(device_h, buffer, format_prop); + + /* 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. + */ + const native_handle_t *handle = + AHardwareBuffer_getNativeHandle(buffer); + int dma_buf = (handle && handle->numFds) ? handle->data[0] : -1; + if (dma_buf < 0) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + + /* All memory types. */ + uint32_t memory_types = (1u << pdevice->memory_properties.memoryTypeCount) - 1; + + pProperties->allocationSize = lseek(dma_buf, 0, SEEK_END); + pProperties->memoryTypeBits = memory_types; + + return VK_SUCCESS; +} + +VkResult +radv_GetMemoryAndroidHardwareBufferANDROID( + VkDevice device_h, + const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo, + struct AHardwareBuffer **pBuffer) +{ + RADV_FROM_HANDLE(radv_device_memory, mem, pInfo->memory); + + /* This should always be set due to the export handle types being set on + * allocation. */ + assert(mem->android_hardware_buffer); + + /* 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 VkExportMemoryAllocateInfo::handleTypes when + * memory was created." + */ + *pBuffer = mem->android_hardware_buffer; + /* Increase refcount. */ + AHardwareBuffer_acquire(mem->android_hardware_buffer); + return VK_SUCCESS; +} + +#endif -- 2.30.2