diff --git a/src/broadcom/vulkan/v3dv_android.c b/src/broadcom/vulkan/v3dv_android.c index 99410a15b24..6c49e5d718a 100644 --- a/src/broadcom/vulkan/v3dv_android.c +++ b/src/broadcom/vulkan/v3dv_android.c @@ -35,6 +35,9 @@ #include #include +#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; +} diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c index aafcd1b3968..540307394b3 100644 --- a/src/broadcom/vulkan/v3dv_device.c +++ b/src/broadcom/vulkan/v3dv_device.c @@ -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); diff --git a/src/broadcom/vulkan/v3dv_formats.c b/src/broadcom/vulkan/v3dv_formats.c index af7b527293b..3eee0ab5bb7 100644 --- a/src/broadcom/vulkan/v3dv_formats.c +++ b/src/broadcom/vulkan/v3dv_formats.c @@ -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 + 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; } diff --git a/src/broadcom/vulkan/v3dv_image.c b/src/broadcom/vulkan/v3dv_image.c index ee653ae1460..b9736aa6850 100644 --- a/src/broadcom/vulkan/v3dv_image.c +++ b/src/broadcom/vulkan/v3dv_image.c @@ -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, diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index af8d5c370d4..4a7e821a255 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -66,6 +66,7 @@ #endif #ifdef ANDROID +#include #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