blob: 89c4f1cb354bbf91689c032c819b6faa93388074 [file] [log] [blame]
/*
* Copyright 2013, Samsung Electronics Co. LTD
*
* 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 toggle 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 LOG_TAG "ExynosCameraMemoryAllocator"
#include "ExynosCameraMemory.h"
namespace android {
gralloc_module_t const *ExynosCameraGrallocAllocator::m_grallocHal;
gralloc_module_t const *ExynosCameraStreamAllocator::m_grallocHal;
ExynosCameraIonAllocator::ExynosCameraIonAllocator()
{
m_ionClient = 0;
m_ionAlign = 0;
m_ionHeapMask = 0;
m_ionFlags = 0;
}
ExynosCameraIonAllocator::~ExynosCameraIonAllocator()
{
ion_close(m_ionClient);
}
status_t ExynosCameraIonAllocator::init(bool isCached)
{
status_t ret = NO_ERROR;
if (m_ionClient == 0) {
m_ionClient = ion_open();
if (m_ionClient < 0) {
ALOGE("ERR(%s):ion_open failed", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
}
m_ionAlign = 0;
m_ionHeapMask = ION_HEAP_SYSTEM_MASK;
m_ionFlags = (isCached == true ?
(ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC ) : 0);
func_exit:
return ret;
}
status_t ExynosCameraIonAllocator::alloc(
int size,
int *fd,
char **addr,
bool mapNeeded)
{
status_t ret = NO_ERROR;
int ionFd = 0;
char *ionAddr = NULL;
if (m_ionClient == 0) {
ALOGE("ERR(%s):allocator is not yet created", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (size == 0) {
ALOGE("ERR(%s):size equals zero", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
ret = ion_alloc_fd(m_ionClient, size, m_ionAlign, m_ionHeapMask, m_ionFlags, &ionFd);
if (ret < 0) {
ALOGE("ERR(%s):ion_alloc_fd(fd=%d) failed(%s)", __FUNCTION__, ionFd, strerror(errno));
ionFd = -1;
ret = INVALID_OPERATION;
goto func_exit;
}
if (mapNeeded == true) {
if (map(size, ionFd, &ionAddr) != NO_ERROR) {
ALOGE("ERR(%s):map failed", __FUNCTION__);
}
}
func_exit:
*fd = ionFd;
*addr = ionAddr;
return ret;
}
status_t ExynosCameraIonAllocator::alloc(
int size,
int *fd,
char **addr,
int mask,
int flags,
bool mapNeeded)
{
status_t ret = NO_ERROR;
int ionFd = 0;
char *ionAddr = NULL;
if (m_ionClient == 0) {
ALOGE("ERR(%s):allocator is not yet created", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (size == 0) {
ALOGE("ERR(%s):size equals zero", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
ret = ion_alloc_fd(m_ionClient, size, m_ionAlign, mask, flags, &ionFd);
if (ret < 0) {
ALOGE("ERR(%s):ion_alloc_fd(fd=%d) failed(%s)", __FUNCTION__, ionFd, strerror(errno));
ionFd = -1;
ret = INVALID_OPERATION;
goto func_exit;
}
if (mapNeeded == true) {
if (map(size, ionFd, &ionAddr) != NO_ERROR) {
ALOGE("ERR(%s):map failed", __FUNCTION__);
}
}
func_exit:
*fd = ionFd;
*addr = ionAddr;
return ret;
}
status_t ExynosCameraIonAllocator::free(
int size,
int *fd,
char **addr,
bool mapNeeded)
{
status_t ret = NO_ERROR;
int ionFd = *fd;
char *ionAddr = *addr;
if (ionFd < 0) {
ALOGE("ERR(%s):ion_fd is lower than zero", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
if (mapNeeded == true) {
if (ionAddr == NULL) {
ALOGE("ERR(%s):ion_addr equals NULL", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
if (munmap(ionAddr, size) < 0) {
ALOGE("ERR(%s):munmap failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
}
ion_close(ionFd);
ionFd = -1;
ionAddr = NULL;
func_exit:
*fd = ionFd;
*addr = ionAddr;
return ret;
}
status_t ExynosCameraIonAllocator::map(int size, int fd, char **addr)
{
status_t ret = NO_ERROR;
char *ionAddr = NULL;
if (size == 0) {
ALOGE("ERR(%s):size equals zero", __FUNCTION__);
ret = BAD_VALUE;
goto func_exit;
}
if (fd <= 0) {
ALOGE("ERR(%s):fd=%d failed", __FUNCTION__, size);
ret = BAD_VALUE;
goto func_exit;
}
ionAddr = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (ionAddr == (char *)MAP_FAILED || ionAddr == NULL) {
ALOGE("ERR(%s):ion_map(size=%d) failed", __FUNCTION__, size);
close(fd);
ionAddr = NULL;
ret = INVALID_OPERATION;
goto func_exit;
}
func_exit:
*addr = ionAddr;
return ret;
}
void ExynosCameraIonAllocator::setIonHeapMask(int mask)
{
m_ionHeapMask |= mask;
}
void ExynosCameraIonAllocator::setIonFlags(int flags)
{
m_ionFlags |= flags;
}
ExynosCameraMHBAllocator::ExynosCameraMHBAllocator()
{
m_allocator = NULL;
}
ExynosCameraMHBAllocator::~ExynosCameraMHBAllocator()
{
}
status_t ExynosCameraMHBAllocator::init(camera_request_memory allocator)
{
m_allocator = allocator;
return NO_ERROR;
}
status_t ExynosCameraMHBAllocator::alloc(
int size,
int *fd,
char **addr,
int numBufs,
camera_memory_t **heap)
{
status_t ret = NO_ERROR;
camera_memory_t *heap_ptr = NULL;
int heapFd = 0;
char *heapAddr = NULL;
if (m_allocator == NULL) {
ALOGE("ERR(%s):m_allocator equals NULL", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
heap_ptr = m_allocator(-1, size, numBufs, &heapFd);
if (heap_ptr == NULL || heapFd < 0) {
ALOGE("ERR(%s):heap_alloc(size=%d) failed", __FUNCTION__, size);
heap_ptr = NULL;
heapFd = -1;
ret = BAD_VALUE;
goto func_exit;
}
heapAddr = (char *)heap_ptr->data;
func_exit:
*fd = heapFd;
*addr = heapAddr;
*heap = heap_ptr;
#ifdef EXYNOS_CAMERA_MEMORY_TRACE
ALOGI("INFO(%s[%d]):[heap.fd=%d] .addr=%p .heap=%p]",
__FUNCTION__, __LINE__, heapFd, heapAddr, heap_ptr);
#endif
return ret;
}
status_t ExynosCameraMHBAllocator::free(
__unused int size,
int *fd,
char **addr,
camera_memory_t **heap)
{
status_t ret = NO_ERROR;
camera_memory_t *heap_ptr = *heap;
int heapFd = *fd;
char *heapAddr = *addr;
if (heap_ptr == NULL) {
ALOGE("ERR(%s):heap_ptr equals NULL", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
heap_ptr->release(heap_ptr);
heapAddr = NULL;
heapFd = -1;
heap_ptr = 0;
func_exit:
*fd = heapFd;
*addr = heapAddr;
*heap = heap_ptr;
return ret;
}
ExynosCameraGrallocAllocator::ExynosCameraGrallocAllocator()
{
m_allocator = NULL;
m_minUndequeueBufferMargin = 0;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&m_grallocHal))
ALOGE("ERR(%s):Loading gralloc HAL failed", __FUNCTION__);
}
ExynosCameraGrallocAllocator::~ExynosCameraGrallocAllocator()
{
m_minUndequeueBufferMargin = 0;
}
status_t ExynosCameraGrallocAllocator::init(
preview_stream_ops *allocator,
int bufCount,
int minUndequeueBufferCount)
{
status_t ret = NO_ERROR;
ret = init(allocator, bufCount, minUndequeueBufferCount, GRALLOC_SET_USAGE_FOR_CAMERA);
return ret;
}
status_t ExynosCameraGrallocAllocator::init(
preview_stream_ops *allocator,
int bufCount,
int minUndequeueBufferCount,
int grallocUsage)
{
status_t ret = NO_ERROR;
m_allocator = allocator;
if( minUndequeueBufferCount < 0 ) {
m_minUndequeueBufferMargin = 0;
} else {
m_minUndequeueBufferMargin = minUndequeueBufferCount;
}
if (setBufferCount(bufCount) != 0) {
ALOGE("ERR(%s):setBufferCount failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (m_allocator->set_usage(m_allocator, grallocUsage) != 0) {
ALOGE("ERR(%s):set_usage failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (m_grallocHal == NULL) {
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&m_grallocHal))
ALOGE("ERR(%s):Loading gralloc HAL failed", __FUNCTION__);
}
func_exit:
return ret;
}
status_t ExynosCameraGrallocAllocator::alloc(
buffer_handle_t **bufHandle,
int fd[],
char *addr[],
int *bufStride,
bool *isLocked)
{
status_t ret = NO_ERROR;
int width = 0;
int height = 0;
void *grallocAddr[3] = {NULL};
int grallocFd[3] = {0};
const private_handle_t *priv_handle = NULL;
int retryCount = 5;
ExynosCameraDurationTimer dequeuebufferTimer;
ExynosCameraDurationTimer lockbufferTimer;
for (int retryCount = 5; retryCount > 0; retryCount--) {
#ifdef EXYNOS_CAMERA_MEMORY_TRACE
ALOGI("INFO(%s[%d]):dequeue_buffer retryCount=%d",
__FUNCTION__, __LINE__, retryCount);
#endif
dequeuebufferTimer.start();
ret = m_allocator->dequeue_buffer(m_allocator, bufHandle, bufStride);
dequeuebufferTimer.stop();
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check dequeue buffer performance, duration(%lld usec)",
__FUNCTION__, __LINE__, dequeuebufferTimer.durationUsecs());
#else
if (dequeuebufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):dequeue_buffer() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)dequeuebufferTimer.durationMsecs());
#endif
if (ret != 0) {
ALOGE("ERR(%s):dequeue_buffer failed", __FUNCTION__);
continue;
}
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle == NULL failed, retry(%d)", __FUNCTION__, retryCount);
continue;
}
lockbufferTimer.start();
ret = m_allocator->lock_buffer(m_allocator, *bufHandle);
lockbufferTimer.stop();
if (ret != 0)
ALOGE("ERR(%s):lock_buffer failed, but go on to the next step ...", __FUNCTION__);
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check lock buffer performance, duration(%lld usec)",
__FUNCTION__, __LINE__, lockbufferTimer.durationUsecs());
#else
if (lockbufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):lock_buffer() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)lockbufferTimer.durationMsecs());
#endif
if (*isLocked == false) {
lockbufferTimer.start();
ret = m_grallocHal->lock(m_grallocHal, **bufHandle, GRALLOC_LOCK_FOR_CAMERA,
0, 0,/* left, top */ width, height, grallocAddr);
lockbufferTimer.stop();
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check grallocHAL lock performance, duration(%lld usec)",
__FUNCTION__, __LINE__, lockbufferTimer.durationUsecs());
#else
if (lockbufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):grallocHAL->lock() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)lockbufferTimer.durationMsecs());
#endif
if (ret != 0) {
ALOGE("ERR(%s):grallocHal->lock failed.. retry", __FUNCTION__);
if (m_allocator->cancel_buffer(m_allocator, *bufHandle) != 0)
ALOGE("ERR(%s):cancel_buffer failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
break;
}
}
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle == NULL failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (*bufHandle == NULL) {
ALOGE("@@@@ERR(%s):*bufHandle == NULL failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
priv_handle = private_handle_t::dynamicCast(**bufHandle);
grallocFd[0] = priv_handle->fd;
grallocFd[1] = priv_handle->fd1;
*isLocked = true;
func_exit:
fd[0] = grallocFd[0];
fd[1] = grallocFd[1];
addr[0] = (char *)grallocAddr[0];
addr[1] = (char *)grallocAddr[1];
return ret;
}
status_t ExynosCameraGrallocAllocator::free(buffer_handle_t *bufHandle, bool isLocked)
{
status_t ret = NO_ERROR;
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle equals NULL", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (isLocked == true) {
if (m_grallocHal->unlock(m_grallocHal, *bufHandle) != 0) {
ALOGE("ERR(%s):grallocHal->unlock failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
}
if (m_allocator->cancel_buffer(m_allocator, bufHandle) != 0) {
ALOGE("ERR(%s):cancel_buffer failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
func_exit:
return ret;
}
status_t ExynosCameraGrallocAllocator::setBufferCount(int bufCount)
{
status_t ret = NO_ERROR;
if (m_allocator->set_buffer_count(m_allocator, bufCount) != 0) {
ALOGE("ERR(%s):set_buffer_count failed [bufCount=%d]", __FUNCTION__, bufCount);
ret = INVALID_OPERATION;
}
return ret;
}
status_t ExynosCameraGrallocAllocator::setBuffersGeometry(
int width,
int height,
int halPixelFormat)
{
status_t ret = NO_ERROR;
if (m_allocator->set_buffers_geometry(
m_allocator,
width, height,
halPixelFormat) != 0) {
ALOGE("ERR(%s):set_buffers_geometry failed", __FUNCTION__);
ret = INVALID_OPERATION;
}
return ret;
}
status_t ExynosCameraGrallocAllocator::getAllocator(preview_stream_ops **allocator)
{
*allocator = m_allocator;
return NO_ERROR;
}
int ExynosCameraGrallocAllocator::getMinUndequeueBuffer()
{
int minUndeqBufCount = 0;
if (m_allocator->get_min_undequeued_buffer_count(m_allocator, &minUndeqBufCount) != 0) {
ALOGE("ERR(%s):enqueue_buffer failed", __FUNCTION__);
return INVALID_OPERATION;
}
return minUndeqBufCount < 2 ? (minUndeqBufCount + m_minUndequeueBufferMargin) : minUndeqBufCount;
}
status_t ExynosCameraGrallocAllocator::dequeueBuffer(
buffer_handle_t **bufHandle,
int fd[],
char *addr[],
bool *isLocked)
{
int bufStride = 0;
if (alloc(bufHandle, fd, addr, &bufStride, isLocked) != 0) {
ALOGE("ERR(%s):alloc failed", __FUNCTION__);
return INVALID_OPERATION;
}
return NO_ERROR;
}
status_t ExynosCameraGrallocAllocator::enqueueBuffer(buffer_handle_t *handle)
{
status_t ret = NO_ERROR;
ExynosCameraDurationTimer enqueuebufferTimer;
enqueuebufferTimer.start();
ret = m_allocator->enqueue_buffer(m_allocator, handle);
enqueuebufferTimer.stop();
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check enqueue buffer performance, duration(%lld usec)",
__FUNCTION__, __LINE__, enqueuebufferTimer.durationUsecs());
#else
if (enqueuebufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):enqueue_buffer() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)enqueuebufferTimer.durationMsecs());
#endif
if (ret != 0) {
ALOGE("ERR(%s):enqueue_buffer failed", __FUNCTION__);
return INVALID_OPERATION;
}
return NO_ERROR;
}
status_t ExynosCameraGrallocAllocator::cancelBuffer(buffer_handle_t *handle)
{
status_t ret = NO_ERROR;
ExynosCameraDurationTimer cancelbufferTimer;
if (m_grallocHal->unlock(m_grallocHal, *handle) != 0) {
ALOGE("ERR(%s):grallocHal->unlock failed", __FUNCTION__);
return INVALID_OPERATION;
}
cancelbufferTimer.start();
ret = m_allocator->cancel_buffer(m_allocator, handle);
cancelbufferTimer.stop();
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check cancel buffer performance, duration(%lld usec)",
__FUNCTION__, __LINE__, cancelbufferTimer.durationUsecs());
#else
if (cancelbufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):cancel_buffer() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)cancelbufferTimer.durationMsecs());
#endif
if (ret != 0) {
ALOGE("ERR(%s):cancel_buffer failed", __FUNCTION__);
return INVALID_OPERATION;
}
return NO_ERROR;
}
ExynosCameraStreamAllocator::ExynosCameraStreamAllocator()
{
m_allocator = NULL;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&m_grallocHal))
ALOGE("ERR(%s):Loading gralloc HAL failed", __FUNCTION__);
}
ExynosCameraStreamAllocator::~ExynosCameraStreamAllocator()
{
}
status_t ExynosCameraStreamAllocator::init(camera3_stream_t *allocator)
{
status_t ret = NO_ERROR;
m_allocator = allocator;
return ret;
}
int ExynosCameraStreamAllocator::lock(
buffer_handle_t **bufHandle,
int fd[],
char *addr[],
bool *isLocked,
int planeCount)
{
int ret = 0;
uint32_t width = 0;
uint32_t height = 0;
uint32_t usage = 0;
uint32_t format = 0;
void *grallocAddr[3] = {NULL};
const private_handle_t *priv_handle = NULL;
int grallocFd[3] = {0};
ExynosCameraDurationTimer lockbufferTimer;
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle equals NULL, failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (*bufHandle == NULL) {
ALOGE("ERR(%s):*bufHandle == NULL, failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
width = m_allocator->width;
height = m_allocator->height;
usage = m_allocator->usage;
format = m_allocator->format;
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
android_ycbcr ycbcr;
lockbufferTimer.start();
ret = m_grallocHal->lock_ycbcr(
m_grallocHal,
**bufHandle,
usage,
0, 0, /* left, top */
width, height,
&ycbcr);
lockbufferTimer.stop();
grallocAddr[0] = ycbcr.y;
break;
default:
lockbufferTimer.start();
ret = m_grallocHal->lock(
m_grallocHal,
**bufHandle,
usage,
0, 0, /* left, top */
width, height,
grallocAddr);
lockbufferTimer.stop();
break;
}
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check grallocHAL lock performance, duration(%lld usec)",
__FUNCTION__, __LINE__, lockbufferTimer.durationUsecs());
#else
if (lockbufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):grallocHAL->lock() duration(%lld msec)",
__FUNCTION__, __LINE__, (long long)lockbufferTimer.durationMsecs());
#endif
if (ret != 0) {
ALOGE("ERR(%s):grallocHal->lock failed.. ", __FUNCTION__);
goto func_exit;
}
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle == NULL failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
if (*bufHandle == NULL) {
ALOGE("@@@@ERR(%s):*bufHandle == NULL failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
priv_handle = private_handle_t::dynamicCast(**bufHandle);
switch (planeCount) {
case 3:
grallocFd[2] = priv_handle->fd2;
case 2:
grallocFd[1] = priv_handle->fd1;
case 1:
grallocFd[0] = priv_handle->fd;
break;
default:
break;
}
*isLocked = true;
func_exit:
switch (planeCount) {
case 3:
fd[2] = grallocFd[2];
addr[2] = (char *)grallocAddr[2];
case 2:
fd[1] = grallocFd[1];
addr[1] = (char *)grallocAddr[1];
case 1:
fd[0] = grallocFd[0];
addr[0] = (char *)grallocAddr[0];
break;
default:
break;
}
return ret;
}
int ExynosCameraStreamAllocator::unlock(buffer_handle_t *bufHandle)
{
int ret = 0;
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle equals NULL", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
ret = m_grallocHal->unlock(m_grallocHal, *bufHandle);
if (ret != 0)
ALOGE("ERR(%s):grallocHal->unlock failed", __FUNCTION__);
func_exit:
return ret;
}
}