anv: adopt common GetAndroidHardwareBufferPropertiesANDROID

ANV currently carries a partial copy of the gralloc mapper's format
resolving code, while the ground truth solely resides inside the
gralloc. The local copy is delicate and unable to maintain compatibility
with different gralloc implementations because AHB formats like
Y8Cb8Cr8_420 and IMPLEMENTATION_DEFINED are flexible formats, and can be
resolved to different underlying drm fourcc formats depending on the
usage and media IPs.

The common impl is more correct as it relies on the info from gralloc
mapper side, and it only sets the minimal set of explicit formats to
avoid hitting spec corner case of allocating out AHB with flexible
formats (missing half of the media usage bits might end up allocating
something different that potentially get resolved to a different
VkFormat as well).

Reviewed-by: Lucas Fryzek <lfryzek@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36866>
This commit is contained in:
Yiwei Zhang 2025-08-20 18:37:38 -07:00 committed by Marge Bot
parent a34eb09c89
commit dcffe932a0

View file

@ -21,176 +21,7 @@
* IN THE SOFTWARE.
*/
#include <vulkan/vk_android_native_buffer.h>
#include <sync/sync.h>
#include "anv_private.h"
#include "vk_android.h"
#include "vk_common_entrypoints.h"
#include "vk_util.h"
#if ANDROID_API_LEVEL >= 26
#include <vndk/hardware_buffer.h>
static inline VkFormat
vk_format_from_android(unsigned android_format, unsigned android_usage)
{
switch (android_format) {
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
case AHARDWAREBUFFER_FORMAT_YV12:
return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
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;
default:
return vk_ahb_format_to_image_format(android_format);
}
}
static VkResult
get_ahw_buffer_format_properties2(
VkDevice device_h,
const struct AHardwareBuffer *buffer,
VkAndroidHardwareBufferFormatProperties2ANDROID *pProperties)
{
ANV_FROM_HANDLE(anv_device, device, device_h);
/* Get a description of buffer contents . */
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
/* Verify description. */
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. */
VkAndroidHardwareBufferFormatProperties2ANDROID *p = pProperties;
p->format = vk_format_from_android(desc.format, desc.usage);
p->externalFormat = p->format;
const struct anv_format *anv_format =
anv_get_format(device->physical, p->format);
/* Default to OPTIMAL tiling but set to linear in case
* of AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER usage.
*/
VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER)
tiling = VK_IMAGE_TILING_LINEAR;
p->formatFeatures =
anv_get_image_format_features2(device->physical, p->format, anv_format,
tiling, 0 /* usage */, 0 /* flags */,
NULL);
/* "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 buffers 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"
*/
p->formatFeatures |=
VK_FORMAT_FEATURE_2_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_NARROW;
p->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
p->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
return VK_SUCCESS;
}
VkResult
anv_GetAndroidHardwareBufferPropertiesANDROID(
VkDevice device_h,
const struct AHardwareBuffer *buffer,
VkAndroidHardwareBufferPropertiesANDROID *pProperties)
{
ANV_FROM_HANDLE(anv_device, dev, device_h);
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) {
VkAndroidHardwareBufferFormatProperties2ANDROID format_prop2 = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID,
};
get_ahw_buffer_format_properties2(device_h, buffer, &format_prop2);
format_prop->format = format_prop2.format;
format_prop->externalFormat = format_prop2.externalFormat;
format_prop->formatFeatures =
vk_format_features2_to_features(format_prop2.formatFeatures);
format_prop->samplerYcbcrConversionComponents =
format_prop2.samplerYcbcrConversionComponents;
format_prop->suggestedYcbcrModel = format_prop2.suggestedYcbcrModel;
format_prop->suggestedYcbcrRange = format_prop2.suggestedYcbcrRange;
format_prop->suggestedXChromaOffset = format_prop2.suggestedXChromaOffset;
format_prop->suggestedYChromaOffset = format_prop2.suggestedYChromaOffset;
}
VkAndroidHardwareBufferFormatProperties2ANDROID *format_prop2 =
vk_find_struct(pProperties->pNext,
ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID);
if (format_prop2)
get_ahw_buffer_format_properties2(device_h, buffer, format_prop2);
/* 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 = (1ull << dev->physical->memory.type_count) - 1;
pProperties->allocationSize = lseek(dma_buf, 0, SEEK_END);
pProperties->memoryTypeBits = memory_types;
return VK_SUCCESS;
}
#endif
/*
* Called from anv_AllocateMemory when import AHardwareBuffer.