venus: adopt common ANB helpers

Below are adopted:
- vk_android_get_anb_layout
- vk_android_import_anb
- vk_android_import_anb_memory

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41145>
This commit is contained in:
Yiwei Zhang 2026-04-23 19:42:10 -07:00 committed by Marge Bot
parent 4c4302d14b
commit 58cc8e1f85
3 changed files with 43 additions and 298 deletions

View file

@ -23,73 +23,6 @@
#define VN_MAX_PLANES 4
struct vn_android_gralloc_buffer_properties {
uint32_t num_planes;
uint64_t modifier;
/* plane order matches VkImageDrmFormatModifierExplicitCreateInfoEXT */
uint32_t offset[4];
uint32_t stride[4];
};
static bool
vn_android_gralloc_get_buffer_properties(
buffer_handle_t handle,
struct vn_android_gralloc_buffer_properties *out_props)
{
struct u_gralloc *gralloc = vk_android_get_ugralloc();
struct u_gralloc_buffer_basic_info info;
/*
* We only support (and care of) CrOS and IMapper v4 gralloc modules
* at this point. They don't need the pixel stride and HAL format
* to be provided externally to them. It allows integrating u_gralloc
* with minimal modifications at this point.
*/
struct u_gralloc_buffer_handle ugb_handle = {
.handle = handle,
.pixel_stride = 0,
.hal_format = 0,
};
if (u_gralloc_get_buffer_basic_info(gralloc, &ugb_handle, &info) != 0) {
vn_log(NULL, "u_gralloc_get_buffer_basic_info failed");
return false;
}
if (info.modifier == DRM_FORMAT_MOD_INVALID) {
vn_log(NULL, "Unexpected DRM_FORMAT_MOD_INVALID");
return false;
}
assert(info.num_planes <= 4);
out_props->num_planes = info.num_planes;
for (uint32_t i = 0; i < info.num_planes; i++) {
if (!info.strides[i]) {
out_props->num_planes = i;
break;
}
out_props->stride[i] = info.strides[i];
out_props->offset[i] = info.offsets[i];
}
/* YVU420 has a chroma order of CrCb. So we must swap the planes for CrCb
* to align with VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM. This is to serve
* VkImageDrmFormatModifierExplicitCreateInfoEXT explicit plane layouts.
*/
if (info.drm_fourcc == DRM_FORMAT_YVU420) {
out_props->stride[1] = info.strides[2];
out_props->offset[1] = info.offsets[2];
out_props->stride[2] = info.strides[1];
out_props->offset[2] = info.offsets[1];
}
out_props->modifier = info.modifier;
return true;
}
static int
vn_android_gralloc_get_dma_buf_fd(const native_handle_t *handle)
{
@ -114,256 +47,57 @@ vn_android_gralloc_get_dma_buf_fd(const native_handle_t *handle)
return handle->data[0];
}
static const VkFormat *
vn_android_format_to_view_formats(VkFormat format, uint32_t *out_count)
{
/* For AHB image prop query and creation, venus overrides the tiling to
* VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, which requires to chain
* VkImageFormatListCreateInfo struct in the corresponding pNext when the
* VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT is set. Those AHB images are assumed
* to be mutable no more than sRGB-ness, and the implementations can fail
* whenever going beyond.
*
* This helper provides the view formats that have sRGB variants for the
* image format that venus supports.
*/
static const VkFormat view_formats_r8g8b8a8[] = {
VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB
};
static const VkFormat view_formats_r8g8b8[] = { VK_FORMAT_R8G8B8_UNORM,
VK_FORMAT_R8G8B8_SRGB };
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
*out_count = ARRAY_SIZE(view_formats_r8g8b8a8);
return view_formats_r8g8b8a8;
break;
case VK_FORMAT_R8G8B8_UNORM:
*out_count = ARRAY_SIZE(view_formats_r8g8b8);
return view_formats_r8g8b8;
break;
default:
/* let the caller handle the fallback case */
*out_count = 0;
return NULL;
}
}
struct vn_android_image_builder {
VkImageCreateInfo create;
VkSubresourceLayout layouts[4];
VkImageDrmFormatModifierExplicitCreateInfoEXT modifier;
VkExternalMemoryImageCreateInfo external;
VkImageFormatListCreateInfo list;
};
static VkResult
vn_android_get_image_builder(struct vn_device *dev,
const VkImageCreateInfo *create_info,
const native_handle_t *handle,
struct vn_android_image_builder *out_builder)
{
/* Android image builder is only used by ANB or AHB. For ANB, Android
* Vulkan loader will never pass the below structs. For AHB, struct
* vn_image_create_deferred_info will never carry below either.
*/
assert(!vk_find_struct_const(
create_info->pNext,
IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT));
assert(!vk_find_struct_const(create_info->pNext,
EXTERNAL_MEMORY_IMAGE_CREATE_INFO));
struct vn_android_gralloc_buffer_properties buf_props;
if (!vn_android_gralloc_get_buffer_properties(handle, &buf_props))
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
/* fill VkImageCreateInfo */
memset(out_builder, 0, sizeof(*out_builder));
out_builder->create = *create_info;
out_builder->create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
/* fill VkImageDrmFormatModifierExplicitCreateInfoEXT */
for (uint32_t i = 0; i < buf_props.num_planes; i++) {
out_builder->layouts[i].offset = buf_props.offset[i];
out_builder->layouts[i].rowPitch = buf_props.stride[i];
}
out_builder->modifier = (VkImageDrmFormatModifierExplicitCreateInfoEXT){
.sType =
VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
.pNext = out_builder->create.pNext,
.drmFormatModifier = buf_props.modifier,
.drmFormatModifierPlaneCount = buf_props.num_planes,
.pPlaneLayouts = out_builder->layouts,
};
out_builder->create.pNext = &out_builder->modifier;
/* fill VkExternalMemoryImageCreateInfo */
out_builder->external = (VkExternalMemoryImageCreateInfo){
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = out_builder->create.pNext,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
};
out_builder->create.pNext = &out_builder->external;
/* fill VkImageFormatListCreateInfo if needed */
if ((create_info->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) &&
!vk_find_struct_const(create_info->pNext,
IMAGE_FORMAT_LIST_CREATE_INFO)) {
/* 12.3. Images
*
* If tiling is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT and flags
* contains VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, then the pNext chain
* must include a VkImageFormatListCreateInfo structure with non-zero
* viewFormatCount.
*/
uint32_t vcount = 0;
const VkFormat *vformats =
vn_android_format_to_view_formats(create_info->format, &vcount);
if (!vformats) {
/* image builder struct persists through the image creation call */
vformats = &out_builder->create.format;
vcount = 1;
}
out_builder->list = (VkImageFormatListCreateInfo){
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
.pNext = out_builder->create.pNext,
.viewFormatCount = vcount,
.pViewFormats = vformats,
};
out_builder->create.pNext = &out_builder->list;
}
return VK_SUCCESS;
}
static VkResult
vn_android_image_from_anb_internal(struct vn_device *dev,
const VkImageCreateInfo *create_info,
const VkNativeBufferANDROID *anb_info,
VkImageCreateInfo *create_info,
const VkAllocationCallbacks *alloc,
struct vn_image **out_img)
{
/* If anb_info->handle points to a classic resouce created from
* virtio_gpu_cmd_resource_create_3d, anb_info->stride is the stride of the
* guest shadow storage other than the host gpu storage.
*
* We also need to pass the correct stride to vn_CreateImage, which will be
* done via VkImageDrmFormatModifierExplicitCreateInfoEXT and will require
* VK_EXT_image_drm_format_modifier support in the host driver. The struct
* needs host storage info which can be queried from cros gralloc.
*/
struct vn_image *img = NULL;
VkResult result;
assert(vk_find_struct_const(create_info->pNext, NATIVE_BUFFER_ANDROID));
struct vn_android_image_builder builder;
result = vn_android_get_image_builder(dev, create_info, anb_info->handle,
&builder);
VkImageDrmFormatModifierExplicitCreateInfoEXT mod_info;
VkSubresourceLayout layouts[VN_MAX_PLANES];
VkResult result = vk_android_get_anb_layout(create_info, &mod_info,
layouts, VN_MAX_PLANES);
if (result != VK_SUCCESS)
return result;
mod_info.pNext = create_info->pNext;
const VkExternalMemoryImageCreateInfo external_info = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = &mod_info,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
};
/* create_info is a already local copy from the caller */
create_info->pNext = &external_info;
/* encoder will strip the Android specific pNext structs */
if (*out_img) {
/* driver side img obj has been created for deferred init like ahb */
img = *out_img;
result = vn_image_init_deferred(dev, &builder.create, img);
if (result != VK_SUCCESS) {
vn_log(dev->instance, "anb: vn_image_init_deferred failed");
return result;
}
} else {
result = vn_image_create(dev, &builder.create, alloc, &img);
if (result != VK_SUCCESS) {
vn_log(dev->instance, "anb: vn_image_create failed");
return result;
}
return vn_image_init_deferred(dev, create_info, *out_img);
}
int dma_buf_fd = vn_android_gralloc_get_dma_buf_fd(anb_info->handle);
if (dma_buf_fd < 0) {
result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto fail;
}
uint32_t mem_type_bits = 0;
result = vn_get_memory_dma_buf_properties(dev, dma_buf_fd, &mem_type_bits);
if (result != VK_SUCCESS)
goto fail;
const VkMemoryRequirements *mem_req =
&img->requirements[0].memory.memoryRequirements;
mem_type_bits &= mem_req->memoryTypeBits;
if (!mem_type_bits) {
vn_log(dev->instance, "anb: no compatible mem type");
result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto fail;
}
int dup_fd = os_dupfd_cloexec(dma_buf_fd);
if (dup_fd < 0) {
vn_log(dev->instance, "anb: os_dupfd_cloexec failed(%d)", errno);
result = (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
: VK_ERROR_OUT_OF_HOST_MEMORY;
goto fail;
}
const bool prefer_dedicated =
img->requirements[0].dedicated.prefersDedicatedAllocation == VK_TRUE;
const VkMemoryDedicatedAllocateInfo dedicated_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.image = vn_image_to_handle(img),
};
const VkImportMemoryFdInfoKHR import_fd_info = {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
.pNext = prefer_dedicated ? &dedicated_info : NULL,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
.fd = dup_fd,
};
const VkMemoryAllocateInfo memory_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &import_fd_info,
.allocationSize = mem_req->size,
.memoryTypeIndex = ffs(mem_type_bits) - 1,
};
VkDeviceMemory mem_handle;
result = vn_AllocateMemory(vn_device_to_handle(dev), &memory_info, alloc,
&mem_handle);
if (result != VK_SUCCESS) {
vn_log(dev->instance, "anb: mem import failed");
/* only need to close the dup_fd on import failure */
close(dup_fd);
goto fail;
}
img->base.vk.anb_memory = mem_handle;
*out_img = img;
return VK_SUCCESS;
fail:
/* this handles mem free for owned import */
vn_DestroyImage(vn_device_to_handle(dev), vn_image_to_handle(img), alloc);
return result;
return vn_image_create(dev, create_info, alloc, out_img);
}
VkResult
vn_android_image_from_anb(struct vn_device *dev,
const VkImageCreateInfo *create_info,
const VkNativeBufferANDROID *anb_info,
const VkAllocationCallbacks *alloc,
struct vn_image **out_img)
{
VkImageCreateInfo local_create = *create_info;
local_create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
struct vn_image *img = NULL;
VkResult result = vn_android_image_from_anb_internal(
dev, create_info, anb_info, alloc, &img);
VkResult result =
vn_android_image_from_anb_internal(dev, &local_create, alloc, &img);
if (result != VK_SUCCESS)
return result;
const VkBindImageMemoryInfo bind_info = {
.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
.image = vn_image_to_handle(img),
.memory = img->base.vk.anb_memory,
};
result = vn_BindImageMemory2(vn_device_to_handle(dev), 1, &bind_info);
result =
vk_android_import_anb(&dev->base.vk, create_info, alloc, &img->base.vk);
if (result != VK_SUCCESS) {
vn_DestroyImage(vn_device_to_handle(dev), vn_image_to_handle(img),
alloc);
@ -378,14 +112,28 @@ VkDeviceMemory
vn_android_get_wsi_memory(struct vn_device *dev,
const VkBindImageMemoryInfo *bind_info)
{
struct vn_image *img = vn_image_from_handle(bind_info->image);
VkImageCreateInfo *create_info = img->base.vk.android_deferred_create_info;
assert(create_info);
const VkNativeBufferANDROID *anb_info =
vk_find_struct_const(bind_info->pNext, NATIVE_BUFFER_ANDROID);
assert(anb_info && anb_info->handle);
struct vn_image *img = vn_image_from_handle(bind_info->image);
/* Inject ANB into the deferred pNext chain to leverage the existing common
* Android helper vk_android_get_anb_layout, which could be refactored to
* take ANB directly instead.
*/
VkNativeBufferANDROID local_anb = *anb_info;
local_anb.pNext = create_info->pNext;
create_info->pNext = &local_anb;
VkResult result = vn_android_image_from_anb_internal(
dev, img->base.vk.android_deferred_create_info, anb_info,
&dev->base.vk.alloc, &img);
dev, create_info, &dev->base.vk.alloc, &img);
if (result != VK_SUCCESS)
return VK_NULL_HANDLE;
result = vk_android_import_anb_memory(&dev->base.vk, &img->base.vk,
anb_info, &dev->base.vk.alloc);
if (result != VK_SUCCESS)
return VK_NULL_HANDLE;

View file

@ -24,7 +24,6 @@
VkResult
vn_android_image_from_anb(struct vn_device *dev,
const VkImageCreateInfo *image_info,
const VkNativeBufferANDROID *anb_info,
const VkAllocationCallbacks *alloc,
struct vn_image **out_img);
@ -42,7 +41,6 @@ vn_android_device_import_ahb(struct vn_device *dev,
static inline VkResult
vn_android_image_from_anb(UNUSED struct vn_device *dev,
UNUSED const VkImageCreateInfo *image_info,
UNUSED const VkNativeBufferANDROID *anb_info,
UNUSED const VkAllocationCallbacks *alloc,
UNUSED struct vn_image **out_img)
{

View file

@ -587,8 +587,7 @@ vn_CreateImage(VkDevice device,
if (wsi_info) {
result = vn_wsi_create_image(dev, pCreateInfo, wsi_info, alloc, &img);
} else if (anb_info) {
result =
vn_android_image_from_anb(dev, pCreateInfo, anb_info, alloc, &img);
result = vn_android_image_from_anb(dev, pCreateInfo, alloc, &img);
} else if (ahb_info) {
result = vn_image_create_deferred(dev, pCreateInfo, alloc, &img);
} else if (swapchain_info) {