blob: 4df3bdbf55dae81495de3af74bb6b7f0924b297a [file] [log] [blame]
/*
* Copyright 2017, 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"
#include <hardware/exynos/dmabuf_container.h>
namespace android {
ExynosCameraIonAllocator::ExynosCameraIonAllocator()
{
m_ionClient = -1;
m_ionAlign = 0;
m_ionHeapMask = 0;
m_ionFlags = 0;
}
ExynosCameraIonAllocator::~ExynosCameraIonAllocator()
{
exynos_ion_close(m_ionClient);
}
status_t ExynosCameraIonAllocator::init(bool isCached)
{
status_t ret = NO_ERROR;
if (m_ionClient < 0) {
m_ionClient = exynos_ion_open();
if (m_ionClient < 0) {
ALOGE("ERR(%s):exynos_ion_open(%d) failed", __FUNCTION__, m_ionClient);
ret = BAD_VALUE;
goto func_exit;
}
}
m_ionAlign = 0;
m_ionHeapMask = EXYNOS_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;
}
ionFd = exynos_ion_alloc(m_ionClient, size, m_ionHeapMask, m_ionFlags);
if (ionFd < 0) {
ALOGE("ERR(%s):exynos_ion_alloc(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;
}
ionFd = exynos_ion_alloc(m_ionClient, size, mask, flags);
if (ionFd < 0) {
ALOGE("ERR(%s):exynos_ion_alloc(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(
__unused 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_close_exit;
}
if (munmap(ionAddr, size) < 0) {
ALOGE("ERR(%s):munmap failed", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_close_exit;
}
}
func_close_exit:
exynos_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__, fd);
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, (fd=%d), (%s)", __FUNCTION__, size, fd, strerror(errno));
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;
}
status_t ExynosCameraIonAllocator::createBufferContainer(int *fd, int batchSize, int *containerFd)
{
int bufferContainerFd = -1;
if (fd == NULL || batchSize < 1 || containerFd == NULL) {
ALOGE("ERR(%s[%d]):Invalid parameters. fd %p batchSize %d containerFd %p",
__FUNCTION__, __LINE__,
fd, batchSize, containerFd);
return BAD_VALUE;
}
bufferContainerFd = dma_buf_merge(*fd, fd + 1, batchSize - 1);
if (bufferContainerFd < 0) {
ALOGE("ERR(%s[%d]):Failed to create BufferContainer. batchSize %d containerFd %d",
__FUNCTION__, __LINE__,
batchSize, bufferContainerFd);
return INVALID_OPERATION;
}
ALOGV("DEBUG(%s[%d]):Success to create BufferContiner. batchSize %d containerFd %d",
__FUNCTION__, __LINE__,
batchSize, bufferContainerFd);
*containerFd = bufferContainerFd;
return NO_ERROR;
}
ExynosCameraStreamAllocator::ExynosCameraStreamAllocator(int actualFormat)
{
m_allocator = NULL;
m_actualFormat = actualFormat;
m_grallocMapper = new GrallocWrapper::Mapper();
}
ExynosCameraStreamAllocator::~ExynosCameraStreamAllocator()
{
if (m_grallocMapper != NULL) {
delete m_grallocMapper;
m_grallocMapper = NULL;
}
}
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 usage = 0;
uint32_t format = 0;
void *grallocAddr[3] = {NULL};
const private_handle_t *priv_handle = NULL;
int grallocFd[3] = {0};
ExynosCameraDurationTimer lockbufferTimer;
GrallocWrapper::Error error = GrallocWrapper::Error::NONE;
GrallocWrapper::YCbCrLayout ycbcrLayout;
GrallocWrapper::IMapper::Rect rect;
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;
}
ycbcrLayout.y = NULL;
ycbcrLayout.cb = NULL;
ycbcrLayout.cr = NULL;
ycbcrLayout.yStride = 0;
ycbcrLayout.cStride = 0;
ycbcrLayout.chromaStep = 0;
rect.left = 0;
rect.top = 0;
rect.width = m_allocator->width;
rect.height = m_allocator->height;
usage = m_allocator->usage;
format = m_allocator->format;
switch (m_actualFormat) {
case HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888:
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RAW16:
case HAL_PIXEL_FORMAT_Y16:
case HAL_PIXEL_FORMAT_Y8:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
case HAL_PIXEL_FORMAT_BLOB:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
if (planeCount == 1) {
lockbufferTimer.start();
error = m_grallocMapper->lock(
**bufHandle,
usage,
rect,
-1, /* acquireFence */
grallocAddr);
lockbufferTimer.stop();
break;
}
default:
lockbufferTimer.start();
/* HACK: YSUM solution for 64bit usage is not supported */
#ifdef USE_YSUM_RECORDING
if ((usage & GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER)
&& (planeCount == 3)) {
error = m_grallocMapper->lock(**bufHandle,
(uint64_t)usage | GRALLOC1_CONSUMER_USAGE_VIDEO_PRIVATE_DATA,
rect,
-1, /* acquireFence */
&ycbcrLayout);
} else
#endif
{
error = m_grallocMapper->lock(**bufHandle,
usage,
rect,
-1, /* acquireFence */
&ycbcrLayout);
}
lockbufferTimer.stop();
break;
}
#if defined (EXYNOS_CAMERA_MEMORY_TRACE_GRALLOC_PERFORMANCE)
ALOGD("DEBUG(%s[%d]):Check grallocHAL lock performance, duration(%ju usec)",
__FUNCTION__, __LINE__, lockbufferTimer.durationUsecs());
#else
if (lockbufferTimer.durationMsecs() > GRALLOC_WARNING_DURATION_MSEC)
ALOGW("WRN(%s[%d]):grallocHAL->lock() duration(%ju msec)",
__FUNCTION__, __LINE__, lockbufferTimer.durationMsecs());
#endif
priv_handle = private_handle_t::dynamicCast(**bufHandle);
if (error != GrallocWrapper::Error::NONE) {
ALOGE("ERR(%s):grallocHal->lock failed.. ", __FUNCTION__);
if (priv_handle == NULL) {
ALOGE("ERR(%s):[H%p]private_handle is NULL",
__FUNCTION__, **bufHandle);
} else {
ALOGE("ERR(%s):[H%p]fd %d/%d/%d usage %x(P%jx/C%jx) format %x(I%jx/F%x) rect %d,%d,%d,%d size %d/%d/%d",
__FUNCTION__,
**bufHandle,
priv_handle->fd, priv_handle->fd1, priv_handle->fd2,
usage, priv_handle->producer_usage, priv_handle->consumer_usage,
format, priv_handle->internal_format, priv_handle->frameworkFormat,
rect.left, rect.top, rect.width, rect.height,
priv_handle->size, priv_handle->size1, priv_handle->size2);
}
ret = INVALID_OPERATION;
goto func_exit;
}
switch (m_actualFormat) {
case HAL_PIXEL_FORMAT_EXYNOS_YV12_M:
grallocFd[2] = priv_handle->fd2;
grallocAddr[2] = ycbcrLayout.cb;
grallocFd[1] = priv_handle->fd1;
grallocAddr[1] = ycbcrLayout.cr;
grallocFd[0] = priv_handle->fd;
grallocAddr[0] = ycbcrLayout.y;
break;
case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M:
case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL:
if ( /* (usage & GRALLOC1_CONSUMER_USAGE_VIDEO_PRIVATE_DATA) &&
* : YSUM solution for 64bit usage is not supported */
(usage & GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER) &&
(m_actualFormat == HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M) &&
(planeCount == 3)) {
/* Use VideoMeta data */
grallocFd[2] = priv_handle->fd2;
grallocAddr[2] = ycbcrLayout.cb;
}
grallocFd[1] = priv_handle->fd1;
grallocAddr[1] = ycbcrLayout.cr;
grallocFd[0] = priv_handle->fd;
grallocAddr[0] = ycbcrLayout.y;
break;
case HAL_PIXEL_FORMAT_YCbCr_420_888:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M:
grallocFd[2] = priv_handle->fd2;
grallocAddr[2] = ycbcrLayout.cr;
grallocFd[1] = priv_handle->fd1;
grallocAddr[1] = ycbcrLayout.cb;
grallocFd[0] = priv_handle->fd;
grallocAddr[0] = ycbcrLayout.y;
break;
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED:
if (usage & GRALLOC1_CONSUMER_USAGE_VIDEO_PRIVATE_DATA) {
/* Use VideoMeta data */
grallocFd[2] = priv_handle->fd2;
grallocAddr[2] = ycbcrLayout.cr;
}
grallocFd[1] = priv_handle->fd1;
grallocAddr[1] = ycbcrLayout.cb;
grallocFd[0] = priv_handle->fd;
grallocAddr[0] = ycbcrLayout.y;
break;
case HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888:
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RAW16:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
case HAL_PIXEL_FORMAT_BLOB:
case HAL_PIXEL_FORMAT_Y8:
case HAL_PIXEL_FORMAT_Y16:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P:
case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I:
case HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I:
case HAL_PIXEL_FORMAT_EXYNOS_CrYCbY_422_I:
case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_SP:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN:
case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN:
default:
grallocFd[0] = priv_handle->fd;
if (grallocAddr[0] == NULL) {
grallocAddr[0] = ycbcrLayout.y;
}
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;
int releaseFence = -1;
if (bufHandle == NULL) {
ALOGE("ERR(%s):bufHandle equals NULL", __FUNCTION__);
ret = INVALID_OPERATION;
goto func_exit;
}
releaseFence = m_grallocMapper->unlock(*bufHandle);
func_exit:
return ret;
}
}