v3dv/android: Add AHardwareBuffer support
The patch allows enabling Vulkan-based UI (SKIA, HWUI) on Android. To enable - add 'TARGET_USES_VULKAN := true' into your device.mk file. Passes: - dEQP-VK.api.external.memory.android_hardware_buffer.* - android.graphics.cts.BasicVulkanGpuTest - android.graphics.cts.MediaVulkanGpuTest Camera preview window works. Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com> Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14195>
This commit is contained in:

committed by
Marge Bot

parent
def20cbb07
commit
733909a637
@@ -35,6 +35,9 @@
|
||||
#include <vulkan/vk_android_native_buffer.h>
|
||||
#include <vulkan/vk_icd.h>
|
||||
|
||||
#include "vk_android.h"
|
||||
#include "vulkan/util/vk_enum_defines.h"
|
||||
|
||||
#include "util/libsync.h"
|
||||
#include "util/log.h"
|
||||
#include "util/os_file.h"
|
||||
@@ -358,3 +361,184 @@ v3dv_GetSwapchainGrallocUsage2ANDROID(
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----------------------------- AHardwareBuffer --------------------------- */
|
||||
|
||||
static VkResult
|
||||
get_ahb_buffer_format_properties2(VkDevice device_h, const struct AHardwareBuffer *buffer,
|
||||
VkAndroidHardwareBufferFormatProperties2ANDROID *pProperties)
|
||||
{
|
||||
V3DV_FROM_HANDLE(v3dv_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. */
|
||||
VkAndroidHardwareBufferFormatProperties2ANDROID *p = pProperties;
|
||||
|
||||
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;
|
||||
|
||||
VkFormatProperties2 format_properties = {.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
|
||||
|
||||
p->format = vk_ahb_format_to_image_format(desc.format);
|
||||
|
||||
VkFormat external_format = p->format;
|
||||
|
||||
if (p->format != VK_FORMAT_UNDEFINED)
|
||||
goto finish;
|
||||
|
||||
/* External format only case
|
||||
*
|
||||
* From vkGetAndroidHardwareBufferPropertiesANDROID spec:
|
||||
* "If the Android hardware buffer has one of the formats listed in the Format
|
||||
* Equivalence table (see spec.), then format must have the equivalent Vulkan
|
||||
* format listed in the table. Otherwise, format may be VK_FORMAT_UNDEFINED,
|
||||
* indicating the Android hardware buffer can only be used with an external format."
|
||||
*
|
||||
* From SKIA source code analysis: p->format MUST be VK_FORMAT_UNDEFINED, if the
|
||||
* format is not in the Equivalence table.
|
||||
*/
|
||||
|
||||
struct u_gralloc_buffer_handle gr_handle = {
|
||||
.handle = AHardwareBuffer_getNativeHandle(buffer),
|
||||
.pixel_stride = desc.stride,
|
||||
.hal_format = desc.format,
|
||||
};
|
||||
|
||||
struct u_gralloc_buffer_basic_info info;
|
||||
|
||||
if (u_gralloc_get_buffer_basic_info(device->gralloc, &gr_handle, &info) != 0)
|
||||
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
||||
|
||||
switch (info.drm_fourcc) {
|
||||
case DRM_FORMAT_YVU420:
|
||||
/* Assuming that U and V planes are swapped earlier */
|
||||
external_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
|
||||
break;
|
||||
case DRM_FORMAT_NV12:
|
||||
external_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
|
||||
break;
|
||||
default:;
|
||||
mesa_loge("Unsupported external DRM format: %d", info.drm_fourcc);
|
||||
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
||||
}
|
||||
|
||||
struct u_gralloc_buffer_color_info color_info;
|
||||
if (u_gralloc_get_buffer_color_info(device->gralloc, &gr_handle, &color_info) == 0) {
|
||||
switch (color_info.yuv_color_space) {
|
||||
case __DRI_YUV_COLOR_SPACE_ITU_REC601:
|
||||
p->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
|
||||
break;
|
||||
case __DRI_YUV_COLOR_SPACE_ITU_REC709:
|
||||
p->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
|
||||
break;
|
||||
case __DRI_YUV_COLOR_SPACE_ITU_REC2020:
|
||||
p->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
p->suggestedYcbcrRange = (color_info.sample_range == __DRI_YUV_NARROW_RANGE) ?
|
||||
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW : VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
|
||||
p->suggestedXChromaOffset = (color_info.horizontal_siting == __DRI_YUV_CHROMA_SITING_0_5) ?
|
||||
VK_CHROMA_LOCATION_MIDPOINT : VK_CHROMA_LOCATION_COSITED_EVEN;
|
||||
p->suggestedYChromaOffset = (color_info.vertical_siting == __DRI_YUV_CHROMA_SITING_0_5) ?
|
||||
VK_CHROMA_LOCATION_MIDPOINT : VK_CHROMA_LOCATION_COSITED_EVEN;
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
v3dv_GetPhysicalDeviceFormatProperties2(v3dv_physical_device_to_handle(device->pdevice),
|
||||
external_format, &format_properties);
|
||||
|
||||
/* v3dv doesn't support direct sampling from linear images but has a logic to copy
|
||||
* from linear to tiled images implicitly before sampling. Therefore expose optimal
|
||||
* features for both linear and optimal tiling.
|
||||
*/
|
||||
p->formatFeatures = format_properties.formatProperties.optimalTilingFeatures;
|
||||
p->externalFormat = external_format;
|
||||
|
||||
/* From vkGetAndroidHardwareBufferPropertiesANDROID spec:
|
||||
* "The formatFeatures member *must* include
|
||||
* VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT and at least one of
|
||||
* VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT or
|
||||
* VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT"
|
||||
*/
|
||||
p->formatFeatures |= VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
v3dv_GetAndroidHardwareBufferPropertiesANDROID(VkDevice device_h,
|
||||
const struct AHardwareBuffer *buffer,
|
||||
VkAndroidHardwareBufferPropertiesANDROID *pProperties)
|
||||
{
|
||||
V3DV_FROM_HANDLE(v3dv_device, dev, device_h);
|
||||
struct v3dv_physical_device *pdevice = dev->pdevice;
|
||||
|
||||
VkResult result;
|
||||
|
||||
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,
|
||||
};
|
||||
result = get_ahb_buffer_format_properties2(device_h, buffer, &format_prop2);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
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) {
|
||||
result = get_ahb_buffer_format_properties2(device_h, buffer, format_prop2);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
|
||||
const native_handle_t *handle = AHardwareBuffer_getNativeHandle(buffer);
|
||||
assert(handle && handle->numFds > 0);
|
||||
pProperties->allocationSize = lseek(handle->data[0], 0, SEEK_END);
|
||||
|
||||
/* All memory types. */
|
||||
pProperties->memoryTypeBits = (1u << pdevice->memory.memoryTypeCount) - 1;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include "git_sha1.h"
|
||||
|
||||
#include "util/build_id.h"
|
||||
#include "util/os_file.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
@@ -2404,11 +2405,6 @@ v3dv_AllocateMemory(VkDevice _device,
|
||||
|
||||
VkResult result;
|
||||
|
||||
if (mem->vk.ahardware_buffer) {
|
||||
result = VK_ERROR_FEATURE_NOT_PRESENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (wsi_info) {
|
||||
result = device_alloc_for_wsi(device, pAllocator, mem, alloc_size);
|
||||
} else if (fd_info && fd_info->handleType) {
|
||||
@@ -2418,11 +2414,20 @@ v3dv_AllocateMemory(VkDevice _device,
|
||||
fd_info->fd, alloc_size, &mem->bo);
|
||||
if (result == VK_SUCCESS)
|
||||
close(fd_info->fd);
|
||||
} else if (mem->vk.ahardware_buffer) {
|
||||
#ifdef ANDROID
|
||||
const native_handle_t *handle = AHardwareBuffer_getNativeHandle(mem->vk.ahardware_buffer);
|
||||
assert(handle->numFds > 0);
|
||||
size_t size = lseek(handle->data[0], 0, SEEK_END);
|
||||
result = device_import_bo(device, pAllocator,
|
||||
handle->data[0], size, &mem->bo);
|
||||
#else
|
||||
result = VK_ERROR_FEATURE_NOT_PRESENT;
|
||||
#endif
|
||||
} else {
|
||||
result = device_alloc(device, mem, alloc_size);
|
||||
}
|
||||
|
||||
done:
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_device_memory_destroy(&device->vk, pAllocator, &mem->vk);
|
||||
return vk_error(device, result);
|
||||
@@ -2668,6 +2673,39 @@ v3dv_BindImageMemory2(VkDevice _device,
|
||||
const VkBindImageMemoryInfo *pBindInfos)
|
||||
{
|
||||
for (uint32_t i = 0; i < bindInfoCount; i++) {
|
||||
#ifdef ANDROID
|
||||
V3DV_FROM_HANDLE(v3dv_device_memory, mem, pBindInfos[i].memory);
|
||||
V3DV_FROM_HANDLE(v3dv_device, device, _device);
|
||||
if (mem != NULL && mem->vk.ahardware_buffer) {
|
||||
AHardwareBuffer_Desc description;
|
||||
const native_handle_t *handle = AHardwareBuffer_getNativeHandle(mem->vk.ahardware_buffer);
|
||||
|
||||
V3DV_FROM_HANDLE(v3dv_image, image, pBindInfos[i].image);
|
||||
AHardwareBuffer_describe(mem->vk.ahardware_buffer, &description);
|
||||
|
||||
struct u_gralloc_buffer_handle gr_handle = {
|
||||
.handle = handle,
|
||||
.pixel_stride = description.stride,
|
||||
.hal_format = description.format,
|
||||
};
|
||||
|
||||
VkResult result = v3dv_gralloc_to_drm_explicit_layout(
|
||||
device->gralloc,
|
||||
&gr_handle,
|
||||
image->android_explicit_layout,
|
||||
image->android_plane_layouts,
|
||||
V3DV_MAX_PLANE_COUNT);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
result = v3dv_update_image_layout(
|
||||
device, image, image->android_explicit_layout->drmFormatModifier,
|
||||
/* disjoint = */ false, image->android_explicit_layout);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
|
||||
vk_find_struct_const(pBindInfos->pNext,
|
||||
BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
|
||||
|
@@ -22,13 +22,18 @@
|
||||
*/
|
||||
|
||||
#include "v3dv_private.h"
|
||||
#include "vk_util.h"
|
||||
#ifdef ANDROID
|
||||
#include "vk_android.h"
|
||||
#endif
|
||||
#include "vk_enum_defines.h"
|
||||
#include "vk_util.h"
|
||||
|
||||
#include "drm-uapi/drm_fourcc.h"
|
||||
#include "util/format/u_format.h"
|
||||
#include "vulkan/wsi/wsi_common.h"
|
||||
|
||||
#include <vulkan/vulkan_android.h>
|
||||
|
||||
const uint8_t *
|
||||
v3dv_get_format_swizzle(struct v3dv_device *device, VkFormat f, uint8_t plane)
|
||||
{
|
||||
@@ -660,6 +665,7 @@ v3dv_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
|
||||
const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
|
||||
const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *drm_format_mod_info = NULL;
|
||||
VkExternalImageFormatProperties *external_props = NULL;
|
||||
UNUSED VkAndroidHardwareBufferUsageANDROID *android_usage = NULL;
|
||||
VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL;
|
||||
VkImageTiling tiling = base_info->tiling;
|
||||
|
||||
@@ -700,6 +706,9 @@ v3dv_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
|
||||
case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
|
||||
external_props = (void *) s;
|
||||
break;
|
||||
case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID:
|
||||
android_usage = (void *)s;
|
||||
break;
|
||||
case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES:
|
||||
ycbcr_props = (void *) s;
|
||||
break;
|
||||
@@ -723,12 +732,26 @@ v3dv_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
|
||||
if (external_props)
|
||||
external_props->externalMemoryProperties = prime_fd_props;
|
||||
break;
|
||||
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
|
||||
if (external_props) {
|
||||
external_props->externalMemoryProperties.exportFromImportedHandleTypes = 0;
|
||||
external_props->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
|
||||
external_props->externalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (android_usage) {
|
||||
#ifdef ANDROID
|
||||
android_usage->androidHardwareBufferUsage =
|
||||
vk_image_usage_to_ahb_usage(base_info->flags, base_info->usage);
|
||||
#endif
|
||||
}
|
||||
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
@@ -490,6 +490,14 @@ v3dv_image_init(struct v3dv_device *device,
|
||||
*/
|
||||
image->vk.create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
|
||||
#ifdef ANDROID
|
||||
/* At this time, an AHB handle is not yet provided.
|
||||
* Image layout will be filled up during vkBindImageMemory2
|
||||
*/
|
||||
if (image->is_ahb)
|
||||
return VK_SUCCESS;
|
||||
#endif
|
||||
|
||||
bool disjoint = image->vk.create_flags & VK_IMAGE_CREATE_DISJOINT_BIT;
|
||||
|
||||
return v3dv_update_image_layout(device, image, modifier, disjoint,
|
||||
@@ -519,7 +527,12 @@ create_image(struct v3dv_device *device,
|
||||
if (native_buffer != NULL)
|
||||
image->is_native_buffer_memory = true;
|
||||
|
||||
if (image->is_native_buffer_memory) {
|
||||
image->is_ahb = external_info && (external_info->handleTypes &
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID);
|
||||
|
||||
assert(!(image->is_ahb && image->is_native_buffer_memory));
|
||||
|
||||
if (image->is_ahb || image->is_native_buffer_memory) {
|
||||
image->android_explicit_layout = vk_alloc2(&device->vk.alloc, pAllocator,
|
||||
sizeof(VkImageDrmFormatModifierExplicitCreateInfoEXT),
|
||||
8,
|
||||
@@ -536,7 +549,9 @@ create_image(struct v3dv_device *device,
|
||||
result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (image->is_native_buffer_memory) {
|
||||
struct u_gralloc_buffer_handle gr_handle = {
|
||||
.handle = native_buffer->handle,
|
||||
.hal_format = native_buffer->format,
|
||||
|
@@ -66,6 +66,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <vndk/hardware_buffer.h>
|
||||
#include "util/u_gralloc/u_gralloc.h"
|
||||
#endif
|
||||
|
||||
@@ -736,6 +737,8 @@ struct v3dv_image {
|
||||
#ifdef ANDROID
|
||||
/* Image is backed by VK_ANDROID_native_buffer, */
|
||||
bool is_native_buffer_memory;
|
||||
/* Image is backed by VK_ANDROID_external_memory_android_hardware_buffer */
|
||||
bool is_ahb;
|
||||
VkImageDrmFormatModifierExplicitCreateInfoEXT *android_explicit_layout;
|
||||
VkSubresourceLayout *android_plane_layouts;
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user