1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

774 lines
21 KiB

/*
* Copyright (c) 2018, Fuzhou Rockchip 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 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 LOG_TAG "CameraHal"
#define LOG_NDEBUG 0
#include <sys/stat.h>
#include <unistd.h>
#include <log/log.h>
#include <ui/GraphicBuffer.h>
#include "ExternalCameraMemManager.h"
#include "BufferAllocatorWrapper.h"
extern "C" {
#define virtual vir
#include <drm.h>
#include <drm_mode.h>
#undef virtual
}
#include <xf86drm.h>
#include <xf86drmMode.h>
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define FMT_NUM_PLANES 1
#define BUFFER_COUNT 4
namespace android {
BufferAllocator* cameraHal_bufferAllocator = NULL;
MemManagerBase::MemManagerBase()
{
mPreviewBufferInfo = NULL;
}
MemManagerBase::~MemManagerBase()
{
mPreviewBufferInfo = NULL;
}
static void *sur_alloc_drm_buf(int *fd,int in_w, int in_h, int in_bpp, unsigned int *drmHandle)
{
int ret;
void *map = NULL;
void *vir_addr = NULL;
struct drm_prime_handle fd_args;
struct drm_mode_map_dumb mmap_arg;
struct drm_mode_destroy_dumb destory_arg;
struct drm_mode_create_dumb alloc_arg;
int drm_fd = drmOpen("rockchip", NULL);
if (drm_fd < 0) {
printf("failed to open rockchip drm: %s\n", strerror(errno));
LOGD("failed to open rockchip drm: %s\n", strerror(errno));
return NULL;
}
memset(&alloc_arg, 0, sizeof(alloc_arg));
alloc_arg.bpp = in_bpp;
alloc_arg.width = in_w;
alloc_arg.height = in_h;
//alloc_arg.flags = (1<<1);
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &alloc_arg);
if (ret) {
LOGE("failed to create dumb buffer: %s\n", strerror(errno));
return NULL;
}
memset(&fd_args, 0, sizeof(fd_args));
fd_args.fd = -1;
fd_args.handle = alloc_arg.handle;;
fd_args.flags = 0;
ret = drmIoctl(drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &fd_args);
if (ret)
{
LOGE("%s: handle_to_fd failed ret=%d,err=%s, handle=%x \n", __FUNCTION__, ret, strerror(errno),fd_args.handle);
return NULL;
}
LOGD("%s: Dump fd = %d \n",__FUNCTION__, fd_args.fd);
*fd = fd_args.fd;
//handle to Virtual address
memset(&mmap_arg, 0, sizeof(mmap_arg));
mmap_arg.handle = alloc_arg.handle;
*drmHandle = alloc_arg.handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg);
if (ret) {
LOGE("%s: failed to create map dumb: %s\n",__FUNCTION__, strerror(errno));
vir_addr = NULL;
goto destory_dumb;
}
vir_addr = map = mmap(0, alloc_arg.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, mmap_arg.offset);
if (map == MAP_FAILED) {
LOGE("%s: failed to mmap buffer: %s\n", __FUNCTION__, strerror(errno));
vir_addr = NULL;
goto destory_dumb;
}
LOGD("%s:alloc map=%x \n",__FUNCTION__, map);
drmClose(drm_fd);
return vir_addr;
destory_dumb:
memset(&destory_arg, 0, sizeof(destory_arg));
destory_arg.handle = alloc_arg.handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destory_arg);
if (ret)
LOGE("failed to destory dumb %d\n", ret);
if(drm_fd)
drmClose(drm_fd);
return vir_addr;
}
static void release_drm_obj(void *addr, int length, int fd, unsigned int drm_handle)
{
if (-1 == munmap(addr, length))
return;
else
{
LOGD("munmap release success addr [%p]\n", addr);
}
int drm_fd = drmOpen("rockchip", NULL);
if (drm_fd < 0) {
LOGE("failed to open rockchip drm: %s\n", strerror(errno));
return ;
}
struct drm_mode_destroy_dumb destory_arg;
close(fd);
memset(&destory_arg, 0, sizeof(destory_arg));
destory_arg.handle = drm_handle;
drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destory_arg);
drmClose(drm_fd);
}
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
static BufferAllocator *render_dma_heap_init()
{
int ret = -1;
BufferAllocator* bufferAllocator = CreateDmabufHeapBufferAllocator();
if (!bufferAllocator) {
LOGE("unable to get allocator\n");
return NULL;
}
ret = MapDmabufHeapNameToIonHeap(bufferAllocator, kDmabufSystemHeapName,
"" /* no mapping for non-legacy */,
0 /* no mapping for non-legacy ion */,
~0 /* legacy ion heap mask */, 0 /* legacy ion heap flag */);
if (ret < 0) {
LOGE("MapDmabufHeapNameToIonHeap failed: %d\n", ret);
return NULL;
}
return bufferAllocator;
}
static void *render_dma_heap_buf(int *export_fd, int width, int height, int bpp)
{
int length = width * height * bpp / 8;
int fd = -1, ret = 0;
size_t i = 0;
void *ptr =NULL;
if(cameraHal_bufferAllocator == NULL )
{
cameraHal_bufferAllocator = render_dma_heap_init();
}
fd = DmabufHeapAlloc(cameraHal_bufferAllocator, kDmabufSystemHeapName, length, 0, 0);
if (fd < 0) {
LOGE("Alloc failed: %d\n", fd);
return NULL;
}
*export_fd = fd;
ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
LOGE("mmap failed\n");
return NULL;
}
LOGD("%s(%d): alloc heap fd is %d addr is %p\n", __FUNCTION__, __LINE__, fd, ptr);
return ptr;
}
static void render_dma_heap_uninit(int *fd, int** addr, int buf_len, int buf_num)
{
for(int i = 0; i < buf_num; i++)
{
munmap(addr[i], buf_len);
close(fd[i]);
}
}
static void errno_exit(const char *s)
{
LOGE("%s error %d, %s\n", s, errno, strerror(errno));
exit(EXIT_FAILURE);
}
void MemManagerBase::setBufferStatus(enum buffer_type_enum buf_type,
unsigned int buf_idx, int status) {
struct bufferinfo_s *buf_info;
switch(buf_type)
{
case PREVIEWBUFFER:
buf_info = mPreviewBufferInfo;
break;
case DISPBUFFER:
buf_info = mDisplayBufferInfo;
break;
default:
LOGE("Buffer type(0x%x) is invaildate",buf_type);
goto getVirAddr_end;
}
if (buf_idx >= buf_info->mNumBffers) {
LOGE("Buffer index(0x%x) is invalidate, Total buffer is 0x%x",
buf_idx,buf_info->mNumBffers);
goto getVirAddr_end;
}
(buf_info+buf_idx)->mStatus = status;
getVirAddr_end:
return;
}
unsigned long MemManagerBase::getBufferAddr(enum buffer_type_enum buf_type,
unsigned int buf_idx, buffer_addr_t addr_type)
{
unsigned long addr = 0x00;
struct bufferinfo_s *buf_info;
switch(buf_type)
{
case PREVIEWBUFFER:
buf_info = mPreviewBufferInfo;
break;
case DISPBUFFER:
buf_info = mDisplayBufferInfo;
break;
default:
LOGE("Buffer type(0x%x) is invaildate",buf_type);
goto getVirAddr_end;
}
if (buf_idx > buf_info->mNumBffers) {
LOGE("Buffer index(0x%x) is invalidate, Total buffer is 0x%x",
buf_idx,buf_info->mNumBffers);
goto getVirAddr_end;
}
if (addr_type == buffer_addr_vir) {
addr = (buf_info+buf_idx)->mVirBaseAddr;
} else if (addr_type == buffer_addr_phy) {
addr = (buf_info+buf_idx)->mPhyBaseAddr;
} else if (addr_type == buffer_sharre_fd) {
addr = (buf_info+buf_idx)->mShareFd;
}
getVirAddr_end:
return addr;
}
int MemManagerBase::getIdleBufferIndex(enum buffer_type_enum buf_type) {
unsigned long addr = 0x00;
struct bufferinfo_s *buf_info;
int index = -1;
switch(buf_type)
{
case PREVIEWBUFFER:
buf_info = mPreviewBufferInfo;
break;
case DISPBUFFER:
buf_info = mDisplayBufferInfo;
break;
default:
LOGE("Buffer type(0x%x) is invaildate",buf_type);
goto getVirAddr_end;
}
for (int i = 0; i < buf_info->mNumBffers; i++)
if ((buf_info+i)->mStatus == 0) {
index = i;
break;
}
if (index >= buf_info->mNumBffers) {
LOGE("Buffer index(0x%x) is invalidate, Total buffer is 0x%x",
index,buf_info->mNumBffers);
return -1;
}
getVirAddr_end:
return index;
}
int MemManagerBase::dump()
{
return 0;
}
GrallocDrmMemManager::GrallocDrmMemManager(bool iommuEnabled)
:MemManagerBase(),
mPreviewData(NULL),
mHandle(NULL),
mOps(NULL)
{
mOps = get_cam_ops(CAM_MEM_TYPE_GRALLOC);
if (mOps) {
mHandle = mOps->init(iommuEnabled ? 1:0,
CAM_MEM_FLAG_HW_WRITE |
CAM_MEM_FLAG_HW_READ |
CAM_MEM_FLAG_SW_WRITE |
CAM_MEM_FLAG_SW_READ,
0);
}
mDisplayData = NULL;
}
GrallocDrmMemManager::~GrallocDrmMemManager()
{
LOGD("destruct mem manager");
if (mPreviewData) {
destroyPreviewBuffer();
mPreviewData = NULL;
}
if (mDisplayData) {
destroyDisplayBuffer();
mDisplayData = NULL;
}
if(mHandle)
mOps->deInit(mHandle);
}
int GrallocDrmMemManager::createGrallocDrmBuffer(struct bufferinfo_s* grallocbuf, unsigned int halPixFmt)
{
int ret =0,i = 0;
int numBufs;
int frame_size;
int cameraFd;
cam_mem_info_t** tmpalloc = NULL;
struct bufferinfo_s* tmp_buf = NULL;
if (!grallocbuf) {
LOGE("gralloc_alloc malloc buffer failed");
return -1;
}
numBufs = grallocbuf->mNumBffers;
frame_size = grallocbuf->mPerBuffersize;
grallocbuf->mBufferSizes = numBufs*PAGE_ALIGN(frame_size);
cameraFd = grallocbuf->mcameraFd;
switch(grallocbuf->mBufType)
{
case PREVIEWBUFFER:
tmpalloc = mPreviewData ;
if((tmp_buf = (struct bufferinfo_s*)malloc(numBufs*sizeof(struct bufferinfo_s))) != NULL) {
mPreviewBufferInfo = tmp_buf;
} else {
LOGE("gralloc_alloc malloc buffer failed");
return -1;
}
break;
case DISPBUFFER:
tmpalloc = mDisplayData ;
if((tmp_buf = (struct bufferinfo_s*)malloc(numBufs*sizeof(struct bufferinfo_s))) != NULL) {
mDisplayBufferInfo = tmp_buf;
} else {
LOGE("gralloc_alloc malloc buffer failed");
return -1;
}
break;
default:
LOGE("do not support this buffer type");
return -1;
}
if(grallocbuf->mIoMethod == IO_METHOD_MMAP){
for(i = 0;i < numBufs; i++) {
#ifndef RK_GRALLOC_4
*tmpalloc = mOps->alloc(mHandle,grallocbuf->mPerBuffersize);
#else
*tmpalloc = mOps->alloc(mHandle,grallocbuf->mPerBuffersize, halPixFmt,
grallocbuf->width, grallocbuf->height);
#endif
if (*tmpalloc) {
LOGD("alloc success");
} else {
LOGE("gralloc mOps->alloc failed");
ret = -1;
break;
}
grallocbuf->mPhyBaseAddr = (unsigned long)((*tmpalloc)->phy_addr);
grallocbuf->mVirBaseAddr = (unsigned long)((*tmpalloc)->vir_addr);
grallocbuf->mPerBuffersize = PAGE_ALIGN(frame_size);
grallocbuf->mShareFd = (unsigned int)((*tmpalloc)->fd);
grallocbuf->mStatus = 0;
LOGD("grallocbuf->mVirBaseAddr=0x%lx, grallocbuf->mShareFd=0x%lx",
grallocbuf->mVirBaseAddr, grallocbuf->mShareFd);
*tmp_buf = *grallocbuf;
tmp_buf++;
tmpalloc++;
}
}else if(grallocbuf->mIoMethod == IO_METHOD_DMABUF)
{
int export_dmafd;
int bpp = 16;
if(grallocbuf->mBufType == PREVIEWBUFFER){
for(i = 0 ; i < numBufs; i++)
{
mPreviewBufferInfo[i].mPerBuffersize = frame_size;
mPreviewBufferInfo[i].mVirBaseAddr = (unsigned long)render_dma_heap_buf(
&export_dmafd, grallocbuf->width, grallocbuf->height, bpp);//(unsigned long)sur_alloc_drm_buf(&export_dmafd, grallocbuf->width, grallocbuf->height,
//bpp, &mDrmHandle);
if(mPreviewBufferInfo[i].mVirBaseAddr == NULL)
{
LOGE("gralloc mOps->alloc failed");
ret = -1;
break;
}
mPreviewBufferInfo[i].mPhyBaseAddr = mPreviewBufferInfo[i].mVirBaseAddr;
mPreviewBufferInfo[i].mShareFd = export_dmafd;
mPreviewBufferInfo[i].mStatus = 0;
mPreviewBufferInfo[i].height = grallocbuf->height;
mPreviewBufferInfo[i].width = grallocbuf->width;
mPreviewBufferInfo[i].mIoMethod = grallocbuf->mIoMethod;
mPreviewBufferInfo[i].mNumBffers = grallocbuf->mNumBffers;
}
}
else if(grallocbuf->mBufType == DISPBUFFER)
{
bpp = 32;
for(i = 0 ; i < numBufs; i++)
{
mDisplayBufferInfo[i].mPerBuffersize = frame_size;
mDisplayBufferInfo[i].mVirBaseAddr = (unsigned long)render_dma_heap_buf(
&export_dmafd, grallocbuf->width, grallocbuf->height, bpp);//(unsigned long)sur_alloc_drm_buf(&export_dmafd, grallocbuf->width, grallocbuf->height,
//32, &mDrmHandle);
if(mDisplayBufferInfo[i].mVirBaseAddr == NULL)
{
LOGE("gralloc mOps->alloc failed");
ret = -1;
break;
}
mDisplayBufferInfo[i].mPhyBaseAddr = mDisplayBufferInfo[i].mVirBaseAddr;
mDisplayBufferInfo[i].mShareFd = export_dmafd;
mDisplayBufferInfo[i].mStatus = 0;
mDisplayBufferInfo[i].height = grallocbuf->height;
mDisplayBufferInfo[i].width = grallocbuf->width;
mDisplayBufferInfo[i].mIoMethod = grallocbuf->mIoMethod;
mDisplayBufferInfo[i].mNumBffers = grallocbuf->mNumBffers;
}
}
}
if(ret < 0) {
LOGE("............................alloc failed !");
while(--i >= 0) {
if(grallocbuf->mIoMethod == IO_METHOD_MMAP){
--tmp_buf;
--tmpalloc;
mOps->free(mHandle,*tmpalloc);
}else{
if(grallocbuf->mBufType == PREVIEWBUFFER){
munmap((void*)mPreviewBufferInfo[i].mVirBaseAddr, grallocbuf->width * grallocbuf->height * 2);
close(mPreviewBufferInfo[i].mShareFd);
}else if(grallocbuf->mBufType == DISPBUFFER)
{
munmap((void*)mDisplayBufferInfo[i].mVirBaseAddr, grallocbuf->width * grallocbuf->height * 4);
close(mDisplayBufferInfo[i].mShareFd);
}
}
}
switch(grallocbuf->mBufType) {
case PREVIEWBUFFER:
if(mPreviewBufferInfo) {
free(mPreviewBufferInfo);
mPreviewBufferInfo = NULL;
}
break;
case DISPBUFFER:
if(mDisplayBufferInfo) {
free(mDisplayBufferInfo);
mDisplayBufferInfo = NULL;
}
break;
default:
break;
}
}
return ret;
}
void GrallocDrmMemManager::destroyGrallocDrmBuffer(buffer_type_enum buftype)
{
cam_mem_info_t** tmpalloc = NULL;
struct bufferinfo_s* tmp_buf = NULL;
int numbufs = 0;
switch(buftype)
{
case PREVIEWBUFFER:
tmpalloc = mPreviewData;
tmp_buf = mPreviewBufferInfo;
numbufs = tmp_buf->mNumBffers;
break;
case DISPBUFFER:
tmpalloc = mDisplayData;
tmp_buf = mDisplayBufferInfo;
numbufs = tmp_buf->mNumBffers;
break;
default:
LOGE("buffer type is wrong !");
break;
}
for(unsigned int i = 0;(tmp_buf && (i < numbufs));i++) {
if(tmp_buf[i].mIoMethod == IO_METHOD_DMABUF)
{
//release_drm_obj((void*)tmp_buf[i].mVirBaseAddr,
// tmp_buf[i].mPerBuffersize, tmp_buf[i].mShareFd,
// mDrmHandle);
LOGD(">>>>> tmp_buf[i].mVirBaseAddr is %x\n", tmp_buf[i].mVirBaseAddr);
if(buftype == PREVIEWBUFFER)
munmap((void*)tmp_buf[i].mVirBaseAddr, tmp_buf[i].width * tmp_buf[i].height * 2);
else
munmap((void*)tmp_buf[i].mVirBaseAddr, tmp_buf[i].width * tmp_buf[i].height * 4);
close(tmp_buf[i].mShareFd);
}
else
{
if(*tmpalloc && (*tmpalloc)->vir_addr) {
LOGD("free graphic buffer");
mOps->free(mHandle,*tmpalloc);
}
tmpalloc++;
}
}
switch(buftype)
{
case PREVIEWBUFFER:
if(mPreviewData)
free(mPreviewData);
mPreviewData = NULL;
if(mPreviewBufferInfo)
free(mPreviewBufferInfo);
mPreviewBufferInfo = NULL;
LOGD("free mPreviewData");
break;
case DISPBUFFER:
if(mDisplayData)
free(mDisplayData);
mDisplayData = NULL;
if(mDisplayBufferInfo)
free(mDisplayBufferInfo);
mDisplayBufferInfo = NULL;
LOGD("free mDisplayData");
break;
default:
LOGE("buffer type is wrong !");
break;
}
if(cameraHal_bufferAllocator != NULL && (mPreviewBufferInfo == NULL) && (mDisplayBufferInfo == NULL))
{
FreeDmabufHeapBufferAllocator(cameraHal_bufferAllocator);
cameraHal_bufferAllocator = NULL;
}
}
int GrallocDrmMemManager::createPreviewBuffer(struct bufferinfo_s* previewbuf)
{
int ret;
Mutex::Autolock lock(mLock);
if(previewbuf->mBufType != PREVIEWBUFFER)
LOGE("the type is not PREVIEWBUFFER");
if(previewbuf->mIoMethod != IO_METHOD_DMABUF){
if(!mPreviewData) {
mPreviewData = (cam_mem_info_t**)malloc(sizeof(cam_mem_info_t*) * previewbuf->mNumBffers);
if(!mPreviewData) {
LOGE("malloc mPreviewData failed!");
ret = -1;
return ret;
}
} else if ((*mPreviewData)->vir_addr) {
LOGD("FREE the preview buffer alloced before firstly");
destroyPreviewBuffer();
}
memset(mPreviewData,0,sizeof(cam_mem_info_t*)* previewbuf->mNumBffers);
}
ret = createGrallocDrmBuffer(previewbuf, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
if (ret == 0) {
LOGD("Preview buffer information(phy:0x%lx vir:0x%lx size:0x%zx)",
mPreviewBufferInfo->mPhyBaseAddr,
mPreviewBufferInfo->mVirBaseAddr,
mPreviewBufferInfo->mBufferSizes);
} else {
LOGE("Preview buffer alloc failed");
if (mPreviewData){
free(mPreviewData);
mPreviewData = NULL;
}
}
return ret;
}
int GrallocDrmMemManager::destroyPreviewBuffer()
{
Mutex::Autolock lock(mLock);
destroyGrallocDrmBuffer(PREVIEWBUFFER);
return 0;
}
int GrallocDrmMemManager::createDisplayBuffer(struct bufferinfo_s* displaybuf)
{
int ret;
Mutex::Autolock lock(mLock);
if(displaybuf->mBufType != DISPBUFFER)
LOGE("the type is not DISPBUFFER");
if(displaybuf->mIoMethod != IO_METHOD_DMABUF){
if(!mDisplayData) {
mDisplayData = (cam_mem_info_t**)malloc(sizeof(cam_mem_info_t*) * displaybuf->mNumBffers);
if(!mDisplayData) {
LOGE("malloc mDisplayData failed!");
ret = -1;
return ret;
}
} else if ((*mDisplayData)->vir_addr) {
LOGD("FREE the display buffer alloced before firstly");
destroyDisplayBuffer();
}
memset(mDisplayData,0,sizeof(cam_mem_info_t*)* displaybuf->mNumBffers);
}
ret = createGrallocDrmBuffer(displaybuf, HAL_PIXEL_FORMAT_RGBA_8888);
if (ret == 0) {
LOGD("Display buffer information(phy:0x%lx vir:0x%lx size:0x%zx)",
mDisplayBufferInfo->mPhyBaseAddr,
mDisplayBufferInfo->mVirBaseAddr,
mDisplayBufferInfo->mBufferSizes);
} else {
LOGE("Display buffer alloc failed");
if (mDisplayData){
free(mDisplayData);
mDisplayData = NULL;
}
}
return ret;
}
int GrallocDrmMemManager::destroyDisplayBuffer()
{
Mutex::Autolock lock(mLock);
destroyGrallocDrmBuffer(DISPBUFFER);
return 0;
}
int GrallocDrmMemManager::flushCacheMem(buffer_type_enum buftype)
{
Mutex::Autolock lock(mLock);
cam_mem_info_t** tmpalloc = NULL;
struct bufferinfo_s* tmp_buf = NULL;
if(mPreviewBufferInfo != NULL && mPreviewBufferInfo[0].mIoMethod == IO_METHOD_DMABUF)
return 0;
switch(buftype)
{
case PREVIEWBUFFER:
tmpalloc = mPreviewData;
tmp_buf = mPreviewBufferInfo;
break;
case DISPBUFFER:
tmpalloc = mDisplayData;
tmp_buf = mDisplayBufferInfo;
break;
default:
LOGE("buffer type is wrong !");
break;
}
if(tmp_buf->mIoMethod == IO_METHOD_MMAP){
for(unsigned int i = 0;(tmp_buf && (i < tmp_buf->mNumBffers));i++) {
if(*tmpalloc && (*tmpalloc)->vir_addr) {
#ifndef RK_GRALLOC_4
int ret = mOps->flush_cache(mHandle, *tmpalloc);
#else
int ret = mOps->flush_cache(mHandle, *tmpalloc, (*tmpalloc)->width, (*tmpalloc)->height);
#endif
if(ret != 0)
LOGD("flush cache failed !");
}
tmpalloc++;
}
}
return 0;
}
}/* namespace android */