blob: 986af11d757d8c9e0b8f13f514f62e4f35f18b66 [file] [log] [blame]
/*
* Copyright (C) 2016-2020 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
#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 <utils/Trace.h>
#include <linux/dma-buf.h>
#include <vector>
#include <sys/ioctl.h>
#include <hardware/hardware.h>
#include <hardware/gralloc1.h>
#include <BufferAllocator/BufferAllocator.h>
#include "mali_gralloc_buffer.h"
#include "gralloc_helper.h"
#include "mali_gralloc_formats.h"
#include "mali_gralloc_usages.h"
#include "core/format_info.h"
#include "core/mali_gralloc_bufferdescriptor.h"
#include "core/mali_gralloc_bufferallocation.h"
#include "mali_gralloc_ion.h"
#include <array>
#include <cassert>
#include <string>
static const char kDmabufSensorDirectHeapName[] = "sensor_direct_heap";
static const char kDmabufFaceauthTpuHeapName[] = "faceauth_tpu-secure";
static const char kDmabufFaceauthImgHeapName[] = "faimg-secure";
static const char kDmabufFaceauthRawImgHeapName[] = "farawimg-secure";
static const char kDmabufFaceauthPrevHeapName[] = "faprev-secure";
static const char kDmabufFaceauthModelHeapName[] = "famodel-secure";
static const char kDmabufVframeSecureHeapName[] = "vframe-secure";
static const char kDmabufVstreamSecureHeapName[] = "vstream-secure";
static const char kDmabufVscalerSecureHeapName[] = "vscaler-secure";
static const char kDmabufFramebufferSecureHeapName[] = "framebuffer-secure";
static const char kDmabufGcmaCameraHeapName[] = "gcma_camera";
static const char kDmabufGcmaCameraUncachedHeapName[] = "gcma_camera-uncached";
BufferAllocator& get_allocator() {
static BufferAllocator allocator;
return allocator;
}
std::string find_first_available_heap(const std::initializer_list<std::string>&& options) {
static auto available_heaps = BufferAllocator::GetDmabufHeapList();
for (const auto& heap: options)
if (available_heaps.find(heap) != available_heaps.end())
return heap;
return "";
}
std::string select_dmabuf_heap(uint64_t usage)
{
struct HeapSpecifier
{
uint64_t usage_bits;
std::string name;
};
static const std::array<HeapSpecifier, 7> exact_usage_heaps =
{{
// Faceauth heaps
{ // isp_image_heap
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GS101_GRALLOC_USAGE_TPU_INPUT,
kDmabufFaceauthImgHeapName
},
{ // isp_internal_heap
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_HW_CAMERA_READ,
kDmabufFaceauthRawImgHeapName
},
{ // isp_preview_heap
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_HW_COMPOSER |
GRALLOC_USAGE_HW_TEXTURE,
kDmabufFaceauthPrevHeapName
},
{ // ml_model_heap
GRALLOC_USAGE_PROTECTED | GS101_GRALLOC_USAGE_TPU_INPUT,
kDmabufFaceauthModelHeapName
},
{ // tpu_heap
GRALLOC_USAGE_PROTECTED | GS101_GRALLOC_USAGE_TPU_OUTPUT | GS101_GRALLOC_USAGE_TPU_INPUT,
kDmabufFaceauthTpuHeapName
},
{
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB,
find_first_available_heap({kDmabufFramebufferSecureHeapName, kDmabufVframeSecureHeapName})
},
{
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER,
find_first_available_heap({kDmabufFramebufferSecureHeapName, kDmabufVframeSecureHeapName})
},
}};
static const std::array<HeapSpecifier, 8> inexact_usage_heaps =
{{
// If GPU, use vframe-secure
{
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE,
kDmabufVframeSecureHeapName
},
{
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_RENDER,
kDmabufVframeSecureHeapName
},
// If HWC but not GPU
{
GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_COMPOSER,
kDmabufVscalerSecureHeapName
},
// Catchall for protected
{
GRALLOC_USAGE_PROTECTED,
kDmabufVframeSecureHeapName
},
// Sensor heap
{
GRALLOC_USAGE_SENSOR_DIRECT_DATA,
kDmabufSensorDirectHeapName
},
// Camera GCMA heap
{
GRALLOC_USAGE_HW_CAMERA_WRITE,
find_first_available_heap({kDmabufGcmaCameraUncachedHeapName, kDmabufSystemUncachedHeapName})
},
// Camera GCMA heap
{
GRALLOC_USAGE_HW_CAMERA_READ,
find_first_available_heap({kDmabufGcmaCameraUncachedHeapName, kDmabufSystemUncachedHeapName})
},
// Catchall to system
{
0,
kDmabufSystemUncachedHeapName
}
}};
for (const HeapSpecifier &heap : exact_usage_heaps)
{
if (usage == heap.usage_bits)
{
return heap.name;
}
}
for (const HeapSpecifier &heap : inexact_usage_heaps)
{
if ((usage & heap.usage_bits) == heap.usage_bits)
{
if (heap.name == kDmabufGcmaCameraUncachedHeapName &&
((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN))
return kDmabufGcmaCameraHeapName;
else if (heap.name == kDmabufSystemUncachedHeapName &&
((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN))
return kDmabufSystemHeapName;
return heap.name;
}
}
return "";
}
int alloc_from_dmabuf_heap(uint64_t usage, size_t size, const std::string& buffer_name = "")
{
ATRACE_CALL();
if (size == 0) { return -1; }
auto heap_name = select_dmabuf_heap(usage);
if (heap_name.empty()) {
MALI_GRALLOC_LOGW("No heap found for usage: %s (0x%" PRIx64 ")", describe_usage(usage).c_str(), usage);
return -EINVAL;
}
ATRACE_NAME(("alloc_from_dmabuf_heap " + heap_name).c_str());
int shared_fd = get_allocator().Alloc(heap_name, size, 0);
if (shared_fd < 0)
{
ALOGE("Allocation failed for heap %s error: %d\n", heap_name.c_str(), shared_fd);
}
if (!buffer_name.empty()) {
if (get_allocator().DmabufSetName(shared_fd, buffer_name)) {
ALOGW("Unable to set buffer name %s: %s", buffer_name.c_str(), strerror(errno));
}
}
return shared_fd;
}
SyncType sync_type_for_flags(const bool read, const bool write)
{
if (read && !write)
{
return SyncType::kSyncRead;
}
else if (write && !read)
{
return SyncType::kSyncWrite;
}
else
{
// Deliberately also allowing "not sure" to map to ReadWrite.
return SyncType::kSyncReadWrite;
}
}
int sync(const int fd, const bool read, const bool write, const bool start)
{
if (start)
{
return get_allocator().CpuSyncStart(fd, sync_type_for_flags(read, write));
}
else
{
return get_allocator().CpuSyncEnd(fd, sync_type_for_flags(read, write));
}
}
int mali_gralloc_ion_sync(const private_handle_t * const hnd,
const bool read,
const bool write,
const bool start)
{
if (hnd == NULL)
{
return -EINVAL;
}
for (int i = 0; i < hnd->fd_count; i++)
{
const int fd = hnd->fds[i];
if (const int ret = sync(fd, read, write, start))
{
return ret;
}
}
return 0;
}
int mali_gralloc_ion_sync_start(const private_handle_t * const hnd,
const bool read,
const bool write)
{
return mali_gralloc_ion_sync(hnd, read, write, true);
}
int mali_gralloc_ion_sync_end(const private_handle_t * const hnd,
const bool read,
const bool write)
{
return mali_gralloc_ion_sync(hnd, read, write, false);
}
void mali_gralloc_ion_free(private_handle_t * const hnd)
{
for (int i = 0; i < hnd->fd_count; i++)
{
close(hnd->fds[i]);
hnd->fds[i] = -1;
}
delete hnd;
}
void mali_gralloc_ion_free_internal(buffer_handle_t * const pHandle,
const uint32_t num_hnds)
{
for (uint32_t i = 0; i < num_hnds; i++)
{
if (pHandle[i] != NULL)
{
private_handle_t * const hnd = (private_handle_t * const)pHandle[i];
mali_gralloc_ion_free(hnd);
}
}
}
int mali_gralloc_ion_allocate_attr(private_handle_t *hnd)
{
ATRACE_CALL();
int idx = hnd->get_share_attr_fd_index();
uint64_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
hnd->fds[idx] = alloc_from_dmabuf_heap(usage, hnd->attr_size);
if (hnd->fds[idx] < 0)
{
MALI_GRALLOC_LOGE("ion_alloc failed");
return -1;
}
hnd->incr_numfds(1);
return 0;
}
/*
* Allocates ION buffers
*
* @param descriptors [in] Buffer request descriptors
* @param numDescriptors [in] Number of descriptors
* @param pHandle [out] Handle for each allocated buffer
* @param shared_backend [out] Shared buffers flag
*
* @return File handle which can be used for allocation, on success
* -1, otherwise.
*/
int mali_gralloc_ion_allocate(const gralloc_buffer_descriptor_t *descriptors,
uint32_t numDescriptors, buffer_handle_t *pHandle,
bool *shared_backend, int ion_fd)
{
ATRACE_CALL();
GRALLOC_UNUSED(shared_backend);
unsigned int priv_heap_flag = 0;
uint64_t usage;
uint32_t i;
for (i = 0; i < numDescriptors; i++)
{
buffer_descriptor_t *bufDescriptor = reinterpret_cast<buffer_descriptor_t *>(descriptors[i]);
assert(bufDescriptor);
assert(bufDescriptor->fd_count >= 0);
assert(bufDescriptor->fd_count <= MAX_FDS);
auto hnd = new private_handle_t(
priv_heap_flag,
bufDescriptor->alloc_sizes,
bufDescriptor->consumer_usage, bufDescriptor->producer_usage,
nullptr, bufDescriptor->fd_count,
bufDescriptor->hal_format, bufDescriptor->alloc_format,
bufDescriptor->width, bufDescriptor->height, bufDescriptor->pixel_stride,
bufDescriptor->layer_count, bufDescriptor->plane_info);
/* Reset the number of valid filedescriptors, we will increment
* it each time a valid fd is added, so we can rely on the
* cleanup functions to close open fds. */
hnd->set_numfds(0);
if (nullptr == hnd)
{
MALI_GRALLOC_LOGE("Private handle could not be created for descriptor:%d in non-shared usecase", i);
mali_gralloc_ion_free_internal(pHandle, i);
return -1;
}
pHandle[i] = hnd;
usage = bufDescriptor->consumer_usage | bufDescriptor->producer_usage;
for (uint32_t fidx = 0; fidx < bufDescriptor->fd_count; fidx++)
{
int& fd = hnd->fds[fidx];
if (ion_fd >= 0 && fidx == 0) {
fd = ion_fd;
} else {
fd = alloc_from_dmabuf_heap(usage, bufDescriptor->alloc_sizes[fidx], bufDescriptor->name);
}
if (fd < 0)
{
MALI_GRALLOC_LOGE("ion_alloc failed for fds[%u] = %d", fidx, fd);
mali_gralloc_ion_free_internal(pHandle, i + 1);
return -1;
}
hnd->incr_numfds(1);
}
}
#if defined(GRALLOC_INIT_AFBC) && (GRALLOC_INIT_AFBC == 1)
ATRACE_NAME("AFBC init block");
unsigned char *cpu_ptr = NULL;
for (i = 0; i < numDescriptors; i++)
{
buffer_descriptor_t *bufDescriptor = reinterpret_cast<buffer_descriptor_t *>(descriptors[i]);
const private_handle_t *hnd = static_cast<const private_handle_t *>(pHandle[i]);
usage = bufDescriptor->consumer_usage | bufDescriptor->producer_usage;
if ((bufDescriptor->alloc_format & MALI_GRALLOC_INTFMT_AFBCENABLE_MASK)
&& !(usage & GRALLOC_USAGE_PROTECTED))
{
{
ATRACE_NAME("mmap");
/* TODO: only map for AFBC buffers */
cpu_ptr =
(unsigned char *)mmap(NULL, bufDescriptor->alloc_sizes[0], PROT_READ | PROT_WRITE, MAP_SHARED, hnd->fds[0], 0);
if (MAP_FAILED == cpu_ptr)
{
MALI_GRALLOC_LOGE("mmap failed for fd ( %d )", hnd->fds[0]);
mali_gralloc_ion_free_internal(pHandle, numDescriptors);
return -1;
}
mali_gralloc_ion_sync_start(hnd, true, true);
}
{
ATRACE_NAME("data init");
/* For separated plane YUV, there is a header to initialise per plane. */
const plane_info_t *plane_info = bufDescriptor->plane_info;
assert(plane_info);
const bool is_multi_plane = hnd->is_multi_plane();
for (int i = 0; i < MAX_PLANES && (i == 0 || plane_info[i].byte_stride != 0); i++)
{
init_afbc(cpu_ptr + plane_info[i].offset,
bufDescriptor->alloc_format,
is_multi_plane,
plane_info[i].alloc_width,
plane_info[i].alloc_height);
}
}
{
ATRACE_NAME("munmap");
mali_gralloc_ion_sync_end(hnd, true, true);
munmap(cpu_ptr, bufDescriptor->alloc_sizes[0]);
}
}
}
#endif
return 0;
}
std::array<void*, MAX_BUFFER_FDS> mali_gralloc_ion_map(private_handle_t *hnd)
{
std::array<void*, MAX_BUFFER_FDS> vaddrs;
vaddrs.fill(nullptr);
uint64_t usage = hnd->producer_usage | hnd->consumer_usage;
/* Do not allow cpu access to secure buffers */
if (usage & (GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_NOZEROED)
&& !(usage & GRALLOC_USAGE_PRIVATE_NONSECURE))
{
return vaddrs;
}
for (int fidx = 0; fidx < hnd->fd_count; fidx++) {
unsigned char *mappedAddress =
(unsigned char *)mmap(NULL, hnd->alloc_sizes[fidx], PROT_READ | PROT_WRITE,
MAP_SHARED, hnd->fds[fidx], 0);
if (MAP_FAILED == mappedAddress)
{
int err = errno;
MALI_GRALLOC_LOGE("mmap( fds[%d]:%d size:%" PRIu64 " ) failed with %s",
fidx, hnd->fds[fidx], hnd->alloc_sizes[fidx], strerror(err));
hnd->dump("map fail");
for (int cidx = 0; cidx < fidx; fidx++)
{
munmap((void*)vaddrs[cidx], hnd->alloc_sizes[cidx]);
vaddrs[cidx] = 0;
}
return vaddrs;
}
vaddrs[fidx] = mappedAddress;
}
return vaddrs;
}
void mali_gralloc_ion_unmap(private_handle_t *hnd, std::array<void*, MAX_BUFFER_FDS>& vaddrs)
{
for (int i = 0; i < hnd->fd_count; i++)
{
int err = 0;
if (vaddrs[i])
{
err = munmap(vaddrs[i], hnd->alloc_sizes[i]);
}
if (err)
{
MALI_GRALLOC_LOGE("Could not munmap base:%p size:%" PRIu64 " '%s'",
(void*)vaddrs[i], hnd->alloc_sizes[i], strerror(errno));
}
else
{
vaddrs[i] = 0;
}
}
hnd->cpu_read = 0;
hnd->cpu_write = 0;
}