android13/hardware/rockchip/libgralloc/utgard/allocator/dmabufheap/dmabufheap.cpp

410 lines
10 KiB
C++

/*
* Copyright (C) 2016-2021 ARM Limited. All rights reserved.
*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ENABLE_DEBUG_LOG
#include "custom_log.h"
#include <string.h>
#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdlib.h>
#include <limits.h>
#include <log/log.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <BufferAllocator/BufferAllocator.h>
#include <linux/dma-buf.h>
#include <vector>
#include <sys/ioctl.h>
#include <hardware/hardware.h>
#include <hardware/gralloc1.h>
#include "gralloc_priv.h"
#include "helper_functions.h"
#include "include/gralloc/formats.h"
#include "usages.h"
#include "core/buffer_descriptor.h"
#include "core/buffer_allocation.h"
#include "core/format_info.h"
#include "allocator/allocator.h"
#include <ion/ion.h>
/* ---------------------------------------------------------------------------------------------------------
* Local Macros
* ---------------------------------------------------------------------------------------------------------
*/
/* 从该 dmabufheap 分配得到的 buffer 是 cached 的, 且其物理地址在 4G 以内 (for dma32). */
static const char kDmabufSystemDma32HeapName[] = "system-dma32";
/* 从该 dmabufheap 分配得到的 buffer 是 uncached 的, 且其物理地址在 4G 以内. */
static const char kDmabufSystemUncachedDma32HeapName[] = "system-uncached-dma32";
#define ION_SYSTEM "ion_system_heap"
#define ION_CMA "linux,cma"
#define DMABUF_CMA "cma"
/* ---------------------------------------------------------------------------------------------------------
* Local Variables
* ---------------------------------------------------------------------------------------------------------
*/
class BufferAllocator* s_buf_allocator;
/* ---------------------------------------------------------------------------------------------------------
* Local Functions Implementation
* ---------------------------------------------------------------------------------------------------------
*/
static bool is_alloc_all_buffers_from_cma_heap_required_via_prop()
{
char value[PROPERTY_VALUE_MAX];
property_get("vendor.gralloc.alloc_all_buf_from_cma_heap", value, "0");
return (0 == strcmp("1", value) );
}
static const char* pick_dmabuf_heap(uint64_t usage)
{
if ( is_alloc_all_buffers_from_cma_heap_required_via_prop() )
{
MALI_GRALLOC_LOGI("to allocate all buffer from cma_heap");
return DMABUF_CMA;
}
if (usage & GRALLOC_USAGE_PROTECTED)
{
MALI_GRALLOC_LOGE("Protected dmabuf_heap memory is not supported yet.");
return NULL;
}
else if ( usage & RK_GRALLOC_USAGE_PHY_CONTIG_BUFFER )
{
return DMABUF_CMA;
}
else if ( usage & RK_GRALLOC_USAGE_WITHIN_4G )
{
if ( (usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN )
{
return kDmabufSystemDma32HeapName; // cacheable dma32
}
else
{
return kDmabufSystemUncachedDma32HeapName; // uncacheable dma32
}
}
else if ( (usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN )
{
return kDmabufSystemHeapName; // cacheable
}
else
{
return kDmabufSystemUncachedHeapName; // uncacheable
}
}
/* 原始定义在 drivers/staging/android/uapi/ion.h 中, 这里的定义必须保持一致. */
#define ION_FLAG_DMA32 4
static int setup_mappings(BufferAllocator *ba)
{
int ret;
/* Setup system-uncached-dma32 heap mapping */
ret = ba->MapNameToIonHeap(kDmabufSystemUncachedDma32HeapName,
ION_SYSTEM,
ION_FLAG_DMA32,
ION_HEAP_TYPE_SYSTEM,
ION_FLAG_DMA32);
if (ret)
{
MALI_GRALLOC_LOGE("No uncached heap! Falling back to system!");
}
/* Setup system-dma32 heap mapping. */
ret = ba->MapNameToIonHeap(kDmabufSystemDma32HeapName,
ION_SYSTEM,
ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC | ION_FLAG_DMA32,
ION_HEAP_TYPE_SYSTEM,
ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC | ION_FLAG_DMA32);
if (ret)
{
MALI_GRALLOC_LOGE("failed to map cached_system_heap.");
}
/* Setup CMA heap */
ret = ba->MapNameToIonHeap(DMABUF_CMA,
ION_CMA, 0,
ION_HEAP_TYPE_DMA, 0);
if (ret)
{
MALI_GRALLOC_LOGE("failed to map cma_heap.");
}
return 0;
}
static int call_dma_buf_sync_ioctl(int fd, uint64_t operation, bool read, bool write)
{
/* Either DMA_BUF_SYNC_START or DMA_BUF_SYNC_END. */
dma_buf_sync sync_args = { operation };
if (read)
{
sync_args.flags |= DMA_BUF_SYNC_READ;
}
if (write)
{
sync_args.flags |= DMA_BUF_SYNC_WRITE;
}
int ret, retry = 5;
do
{
ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync_args);
retry--;
} while ((ret == -EAGAIN || ret == -EINTR) && retry);
if (ret < 0)
{
MALI_GRALLOC_LOGE("ioctl: %#" PRIx64 ", flags: %#" PRIx64 "failed with code %d: %s",
(uint64_t)DMA_BUF_IOCTL_SYNC, (uint64_t)sync_args.flags, ret, strerror(errno));
return -errno;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int allocator_sync_start(const private_handle_t *handle, bool read, bool write)
{
if (handle == nullptr)
{
return -EINVAL;
}
return call_dma_buf_sync_ioctl(handle->share_fd, DMA_BUF_SYNC_START, read, write);
}
int allocator_sync_end(const private_handle_t *handle, bool read, bool write)
{
if (handle == nullptr)
{
return -EINVAL;
}
return call_dma_buf_sync_ioctl(handle->share_fd, DMA_BUF_SYNC_END, read, write);
}
void allocator_free(private_handle_t *handle)
{
if (handle == nullptr)
{
return;
}
/* Buffer might be unregistered already so we need to assure we have a valid handle */
if (handle->base != 0)
{
if (munmap(handle->base, handle->size) != 0)
{
MALI_GRALLOC_LOGE("Failed to munmap handle %p", handle);
}
}
close(handle->share_fd);
handle->share_fd = -1;
}
int allocator_allocate(const buffer_descriptor_t *descriptor, private_handle_t **out_handle)
{
unsigned int priv_heap_flag = private_handle_t::PRIV_FLAGS_USES_DBH;
uint64_t usage;
int shared_fd = -1;
private_handle_t *handle = nullptr;
int ret = 0;
if ( NULL == s_buf_allocator )
{
s_buf_allocator = new BufferAllocator();
if ( NULL == s_buf_allocator )
{
MALI_GRALLOC_LOGE("Failed to new a BufferAllocator instance.");
return -1;
}
ret = setup_mappings(s_buf_allocator);
if (ret)
{
MALI_GRALLOC_LOGE("Could not setup heap mappings!");
return ret;
}
}
usage = descriptor->consumer_usage | descriptor->producer_usage;
const char* heap_name = pick_dmabuf_heap(usage);
if ( NULL == heap_name )
{
MALI_GRALLOC_LOGE("Failed to find an appropriate dmabuf_heap.");
ret = -1;
goto fail;
}
shared_fd = s_buf_allocator->Alloc(heap_name, descriptor->size);
if (shared_fd < 0)
{
MALI_GRALLOC_LOGE("Alloc failed.");
ret = -ENOMEM;
goto fail;
}
handle = make_private_handle(
priv_heap_flag, descriptor->size, descriptor->consumer_usage,
descriptor->producer_usage, shared_fd, descriptor->hal_format, descriptor->alloc_format,
descriptor->width, descriptor->height, descriptor->size, descriptor->layer_count,
descriptor->plane_info,
descriptor->plane_info[0].byte_stride,
descriptor->pixel_stride);
if (nullptr == handle)
{
MALI_GRALLOC_LOGE("Private handle could not be created for descriptor");
ret = -ENOMEM;
goto fail;
}
else
{
/* Ownership transferred to handle. */
shared_fd = -1;
}
if (usage & GRALLOC_USAGE_PROTECTED)
{
goto success;
}
/*-------------------------------------------------------*/
ret = allocator_map(handle);
if (ret != 0)
{
MALI_GRALLOC_LOGE("mmap failed, fd ( %d )", handle->share_fd);
goto fail;
}
/* 标识当前 buf 已经被 map. */
handle->lockState = private_handle_t::LOCK_STATE_MAPPED;
/*-------------------------------------------------------*/
#ifndef GRALLOC_INIT_AFBC
#define GRALLOC_INIT_AFBC 0
#endif
if (GRALLOC_INIT_AFBC && is_format_afbc(descriptor->alloc_format))
{
allocator_sync_start(handle, true, true);
/* For separated plane YUV, there is a header to initialise per plane. */
const plane_info_t *plane_info = descriptor->plane_info;
const bool is_multi_plane = handle->is_multi_plane();
for (int i = 0; i < MAX_PLANES && (i == 0 || plane_info[i].byte_stride != 0); i++)
{
init_afbc(static_cast<uint8_t *>(handle->base) + plane_info[i].offset,
descriptor->alloc_format,
is_multi_plane,
plane_info[i].alloc_width,
plane_info[i].alloc_height);
}
allocator_sync_end(handle, true, true);
}
success:
*out_handle = handle;
return 0;
fail:
if (shared_fd != -1)
{
close(shared_fd);
}
if (handle != nullptr)
{
allocator_free(handle);
native_handle_delete(handle);
}
return ret;
}
int allocator_map(private_handle_t *handle)
{
if (handle == nullptr)
{
return -EINVAL;
}
void *hint = nullptr;
int protection = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED;
off_t page_offset = 0;
void *mapping = mmap(hint, handle->size, protection, flags, handle->share_fd, page_offset);
if (MAP_FAILED == mapping)
{
MALI_GRALLOC_LOGE("mmap(share_fd = %d) failed: %s", handle->share_fd, strerror(errno));
return -errno;
}
handle->base = static_cast<std::byte *>(mapping) + handle->offset;
return 0;
}
void allocator_unmap(private_handle_t *handle)
{
if (handle == nullptr)
{
return;
}
void *base = static_cast<std::byte *>(handle->base) - handle->offset;
if (munmap(base, handle->size) < 0)
{
MALI_GRALLOC_LOGE("Could not munmap base:%p size:%d '%s'", base, handle->size, strerror(errno));
}
else
{
handle->base = 0;
handle->cpu_read = 0;
handle->cpu_write = 0;
}
}
void allocator_close(void)
{
return;
}