mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-25 23:28:12 +02:00
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>
247 lines
8.2 KiB
C
247 lines
8.2 KiB
C
/*
|
|
* Copyright 2021 Google LLC
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* based in part on anv and radv which are:
|
|
* Copyright © 2015 Intel Corporation
|
|
* Copyright © 2016 Red Hat
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
*/
|
|
|
|
#include "vn_android.h"
|
|
|
|
#include <dlfcn.h>
|
|
#include <vndk/hardware_buffer.h>
|
|
|
|
#include "util/os_file.h"
|
|
#include "util/u_gralloc/u_gralloc.h"
|
|
|
|
#include "vn_buffer.h"
|
|
#include "vn_device.h"
|
|
#include "vn_device_memory.h"
|
|
#include "vn_image.h"
|
|
|
|
#define VN_MAX_PLANES 4
|
|
|
|
static int
|
|
vn_android_gralloc_get_dma_buf_fd(const native_handle_t *handle)
|
|
{
|
|
/* There can be multiple fds wrapped inside a native_handle_t, but we
|
|
* expect the 1st one pointing to the dma_buf. For multi-planar format,
|
|
* there should only exist one undelying dma_buf. The other fd(s) could be
|
|
* dups to the same dma_buf or point to the shared memory used to store
|
|
* gralloc buffer metadata.
|
|
*/
|
|
assert(handle);
|
|
|
|
if (handle->numFds < 1) {
|
|
vn_log(NULL, "handle->numFds is %d, expected >= 1", handle->numFds);
|
|
return -1;
|
|
}
|
|
|
|
if (handle->data[0] < 0) {
|
|
vn_log(NULL, "handle->data[0] < 0");
|
|
return -1;
|
|
}
|
|
|
|
return handle->data[0];
|
|
}
|
|
|
|
static VkResult
|
|
vn_android_image_from_anb_internal(struct vn_device *dev,
|
|
VkImageCreateInfo *create_info,
|
|
const VkAllocationCallbacks *alloc,
|
|
struct vn_image **out_img)
|
|
{
|
|
assert(vk_find_struct_const(create_info->pNext, NATIVE_BUFFER_ANDROID));
|
|
|
|
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 */
|
|
return vn_image_init_deferred(dev, create_info, *out_img);
|
|
}
|
|
|
|
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 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, &local_create, alloc, &img);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
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);
|
|
return result;
|
|
}
|
|
|
|
*out_img = img;
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
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);
|
|
|
|
/* 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, 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;
|
|
|
|
return img->base.vk.anb_memory;
|
|
}
|
|
|
|
static VkResult
|
|
vn_android_ahb_image_init(struct vn_device *dev,
|
|
struct AHardwareBuffer *ahb,
|
|
struct vn_image *img)
|
|
{
|
|
VkImageCreateInfo *create_info = img->base.vk.android_deferred_create_info;
|
|
VkResult result;
|
|
|
|
assert(create_info);
|
|
|
|
VkImageDrmFormatModifierExplicitCreateInfoEXT mod_info;
|
|
VkSubresourceLayout layouts[VN_MAX_PLANES];
|
|
result = vk_android_get_ahb_layout(ahb, &mod_info, layouts, VN_MAX_PLANES);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
__vk_append_struct(create_info, &mod_info);
|
|
|
|
VkExternalMemoryImageCreateInfo external_info = {
|
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
|
};
|
|
__vk_append_struct(create_info, &external_info);
|
|
|
|
return vn_image_init_deferred(dev, create_info, img);
|
|
}
|
|
|
|
VkResult
|
|
vn_android_device_import_ahb(struct vn_device *dev,
|
|
struct vn_device_memory *mem,
|
|
const struct VkMemoryAllocateInfo *alloc_info)
|
|
{
|
|
struct vk_device_memory *mem_vk = &mem->base.vk;
|
|
VkResult result;
|
|
|
|
const native_handle_t *handle =
|
|
AHardwareBuffer_getNativeHandle(mem_vk->ahardware_buffer);
|
|
int dma_buf_fd = vn_android_gralloc_get_dma_buf_fd(handle);
|
|
if (dma_buf_fd < 0)
|
|
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
|
|
|
uint32_t mem_type_bits = 0;
|
|
result = vn_get_memory_dma_buf_properties(dev, dma_buf_fd, &mem_type_bits);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
const VkMemoryDedicatedAllocateInfo *dedicated_info =
|
|
vk_find_struct_const(alloc_info->pNext, MEMORY_DEDICATED_ALLOCATE_INFO);
|
|
|
|
VkMemoryRequirements mem_reqs;
|
|
if (dedicated_info && dedicated_info->image != VK_NULL_HANDLE) {
|
|
struct vn_image *img = vn_image_from_handle(dedicated_info->image);
|
|
result = vn_android_ahb_image_init(dev, mem_vk->ahardware_buffer, img);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
mem_reqs = img->requirements[0].memory.memoryRequirements;
|
|
mem_reqs.memoryTypeBits &= mem_type_bits;
|
|
} else if (dedicated_info && dedicated_info->buffer != VK_NULL_HANDLE) {
|
|
struct vn_buffer *buf = vn_buffer_from_handle(dedicated_info->buffer);
|
|
mem_reqs = buf->requirements.memory.memoryRequirements;
|
|
mem_reqs.memoryTypeBits &= mem_type_bits;
|
|
} else {
|
|
mem_reqs.size = mem_vk->size;
|
|
mem_reqs.memoryTypeBits = mem_type_bits;
|
|
}
|
|
|
|
if (!mem_reqs.memoryTypeBits)
|
|
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
|
|
|
if (!((1 << mem_vk->memory_type_index) & mem_reqs.memoryTypeBits))
|
|
mem_vk->memory_type_index = ffs(mem_reqs.memoryTypeBits) - 1;
|
|
|
|
mem_vk->size = mem_reqs.size;
|
|
|
|
int dup_fd = os_dupfd_cloexec(dma_buf_fd);
|
|
if (dup_fd < 0)
|
|
return (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
|
|
: VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
/* Spec requires AHB export info to be present, so we must strip it. In
|
|
* practice, the AHB import path here only needs the main allocation info
|
|
* and the dedicated_info.
|
|
*/
|
|
VkMemoryDedicatedAllocateInfo local_dedicated_info;
|
|
/* Override when dedicated_info exists and is not the tail struct. */
|
|
if (dedicated_info && dedicated_info->pNext) {
|
|
local_dedicated_info = *dedicated_info;
|
|
local_dedicated_info.pNext = NULL;
|
|
dedicated_info = &local_dedicated_info;
|
|
}
|
|
const VkMemoryAllocateInfo local_alloc_info = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.pNext = dedicated_info,
|
|
.allocationSize = mem_vk->size,
|
|
.memoryTypeIndex = mem_vk->memory_type_index,
|
|
};
|
|
result =
|
|
vn_device_memory_import_dma_buf(dev, mem, &local_alloc_info, dup_fd);
|
|
if (result != VK_SUCCESS) {
|
|
close(dup_fd);
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|