blob: 9767cd4f05ddd513420ebb8b46d44315897a1ac9 [file] [log] [blame]
/*
* Copyright (C) 2019 MediaTek Inc.
*
* 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 "MtkCam/GrallocHeap"
//
#include "BaseImageBufferHeap.h"
#include <camera_buffer_handle.h>
#include <cros-camera/camera_buffer_manager.h>
#include <linux/videodev2.h>
#include <memory>
#include <mtkcam/utils/imgbuf/IGbmImageBufferHeap.h>
#include <vector>
using NSCam::IGbmImageBufferHeap;
using NSCam::NSImageBufferHeap::BaseImageBufferHeap;
/******************************************************************************
* Image Buffer Heap (Gralloc).
******************************************************************************/
namespace {
class GbmImageBufferHeap
: public IGbmImageBufferHeap,
public NSCam::NSImageBufferHeap::BaseImageBufferHeap {
friend class IGbmImageBufferHeap;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// IGbmImageBufferHeap Interface.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public: //// Accessors.
virtual void* getHWBuffer() { return reinterpret_cast<void*>(this); }
virtual buffer_handle_t getBufferHandle() const { return mpHwBuffer; }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// BaseImageBufferHeap Interface.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
protected: ////
virtual char const* impGetMagicName() const { return magicName(); }
virtual HeapInfoVect_t const& impGetHeapInfo() const { return mvHeapInfo; }
virtual MBOOL impInit(BufInfoVect_t const& rvBufInfo);
virtual MBOOL impUninit();
virtual MBOOL impReconfig(BufInfoVect_t const& rvBufInfo) { return MFALSE; }
public: ////
virtual MBOOL impLockBuf(char const* szCallerName,
MINT usage,
BufInfoVect_t const& rvBufInfo);
virtual MBOOL impUnlockBuf(char const* szCallerName,
MINT usage,
BufInfoVect_t const& rvBufInfo);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Definitions.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
protected:
typedef std::vector<std::shared_ptr<BufInfo> > MyBufInfoVect_t;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Implementations.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
protected: ////
virtual MVOID doDeallocGB();
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Instantiation.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public: //// Destructor/Constructors.
virtual ~GbmImageBufferHeap();
GbmImageBufferHeap(char const* szCallerName,
AllocImgParam_t const& rImgParam);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Data Members.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
protected: //// Info to Allocate.
size_t mImgFormat; // image format.
MSize mImgSize; // image size.
protected: //// Info of Allocated Result.
HeapInfoVect_t mvHeapInfo; //
MyBufInfoVect_t mvBufInfo; //
buffer_handle_t mpHwBuffer;
size_t mBufStridesInBytesToAlloc[3]; // buffer strides in bytes.
size_t mBufBoundaryInBytesToAlloc[3]; // the address will be a multiple of
// boundary in bytes, which must be a
// power of two.
size_t mBufsize;
private:
cros::CameraBufferManager* mGbmBufferManager;
};
}; // namespace
/******************************************************************************
*
******************************************************************************/
std::shared_ptr<IGbmImageBufferHeap> IGbmImageBufferHeap::create(
char const* szCallerName,
AllocImgParam_t const& rImgParam,
MBOOL const enableLog) {
auto pHeap = std::make_shared<GbmImageBufferHeap>(szCallerName, rImgParam);
if (!pHeap) {
CAM_LOGE("Fail to new");
return NULL;
}
//
if (!pHeap->onCreate(std::dynamic_pointer_cast<BaseImageBufferHeap>(pHeap),
rImgParam.imgSize, rImgParam.imgFormat,
rImgParam.bufSize, enableLog)) {
CAM_LOGE("onCreate fail");
return nullptr;
}
//
return pHeap;
}
/******************************************************************************
*
******************************************************************************/
GbmImageBufferHeap::GbmImageBufferHeap(char const* szCallerName,
AllocImgParam_t const& rImgParam)
: BaseImageBufferHeap(szCallerName),
mImgFormat(rImgParam.imgFormat),
mImgSize(rImgParam.imgSize),
mpHwBuffer(nullptr),
mBufsize(0),
mGbmBufferManager(nullptr) {
::memcpy(mBufStridesInBytesToAlloc, rImgParam.bufStridesInBytes,
sizeof(mBufStridesInBytesToAlloc));
::memcpy(mBufBoundaryInBytesToAlloc, rImgParam.bufBoundaryInBytes,
sizeof(mBufBoundaryInBytesToAlloc));
}
GbmImageBufferHeap::~GbmImageBufferHeap() {
impUninit();
}
/******************************************************************************
*
******************************************************************************/
MBOOL
GbmImageBufferHeap::impInit(BufInfoVect_t const& rvBufInfo) {
bool ret = MFALSE;
uint32_t stride = 0;
size_t allocateSize = 0;
int err;
MY_LOGD("[w,h]=[%d,%d],format=%x", mImgSize.w, mImgSize.h, mImgFormat);
// Allocate memory and setup mBufHeapInfo & rBufHeapInfo.
mGbmBufferManager = cros::CameraBufferManager::GetInstance();
if (mGbmBufferManager == nullptr) {
MY_LOGE("GetInstance failed!");
return false;
}
for (int i = 0; i < getPlaneCount(); i++) {
allocateSize += helpQueryBufSizeInBytes(i, mBufStridesInBytesToAlloc[i]);
}
MY_LOGD("allocateSize = %zu", allocateSize);
mvHeapInfo.reserve(getPlaneCount());
mvBufInfo.reserve(getPlaneCount());
for (int i = 0; i < getPlaneCount(); i++) {
auto pHeapInfo = std::make_shared<HeapInfo>();
mvHeapInfo.push_back(pHeapInfo);
auto pBufInfo = std::make_shared<BufInfo>();
mvBufInfo.push_back(pBufInfo);
}
if (mImgFormat == eImgFmt_NV12) {
uint32_t halformat = HAL_PIXEL_FORMAT_YCbCr_420_888;
err = mGbmBufferManager->Allocate(mImgSize.w, mImgSize.h, halformat,
GRALLOC_USAGE_HW_CAMERA_WRITE,
cros::GRALLOC, &mpHwBuffer, &stride);
if (err != 0) {
MY_LOGE("Allocate handle failed! %d", ret);
return false;
}
for (int i = 0; i < getPlaneCount(); i++) {
mvHeapInfo[i]->heapID = mpHwBuffer->data[i];
mBufStridesInBytesToAlloc[i] =
mGbmBufferManager->GetPlaneStride(mpHwBuffer, i);
mvBufInfo[i]->stridesInBytes =
mGbmBufferManager->GetPlaneStride(mpHwBuffer, i);
mvBufInfo[i]->sizeInBytes =
mGbmBufferManager->GetPlaneSize(mpHwBuffer, i);
mvBufInfo[i]->offsetInBytes =
mGbmBufferManager->GetPlaneOffset(mpHwBuffer, i);
mBufsize += mvBufInfo[i]->sizeInBytes;
}
} else {
err = mGbmBufferManager->Allocate(allocateSize, 1, HAL_PIXEL_FORMAT_BLOB,
GRALLOC_USAGE_HW_CAMERA_WRITE,
cros::GRALLOC, &mpHwBuffer, &stride);
if (err != 0) {
MY_LOGE("Allocate handle failed! %d", ret);
return false;
}
off_t offset = 0;
for (int i = 0; i < getPlaneCount(); i++) {
mvHeapInfo[i]->heapID = mpHwBuffer->data[0];
mvBufInfo[i]->stridesInBytes = mBufStridesInBytesToAlloc[i];
mvBufInfo[i]->sizeInBytes =
helpQueryBufSizeInBytes(i, mBufStridesInBytesToAlloc[i]);
mvBufInfo[i]->offsetInBytes = offset;
offset += mvBufInfo[i]->sizeInBytes;
mBufsize += mvBufInfo[i]->sizeInBytes;
}
}
for (int i = 0; i < getPlaneCount(); i++) {
rvBufInfo[i]->stridesInBytes = mvBufInfo[i]->stridesInBytes;
rvBufInfo[i]->sizeInBytes = mvBufInfo[i]->sizeInBytes;
rvBufInfo[i]->offsetInBytes = mvBufInfo[i]->offsetInBytes;
}
MY_LOGD("mBufsize = %zu", mBufsize);
ret = MTRUE;
if (!ret) {
doDeallocGB();
mvHeapInfo.clear();
mvBufInfo.clear();
}
MY_LOGD_IF(getLogCond(), "- ret:%d", ret);
return ret;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
GbmImageBufferHeap::impUninit() {
doDeallocGB();
mvHeapInfo.clear();
mvBufInfo.clear();
//
MY_LOGD_IF(getLogCond(), "-");
return MTRUE;
}
/******************************************************************************
*
******************************************************************************/
MVOID
GbmImageBufferHeap::doDeallocGB() {
if (mpHwBuffer != nullptr) {
int ret = mGbmBufferManager->Free(mpHwBuffer);
if (ret) {
MY_LOGE("@%s: call Deregister fail, mHandle:%p, ret:%d", __FUNCTION__,
mpHwBuffer, ret);
}
mpHwBuffer = nullptr;
}
}
/******************************************************************************
*
******************************************************************************/
MBOOL
GbmImageBufferHeap::impLockBuf(char const* szCallerName,
MINT usage,
BufInfoVect_t const& rvBufInfo) {
int v4l2Fmt = mGbmBufferManager->GetV4L2PixelFormat(mpHwBuffer);
uint32_t planeNum = mGbmBufferManager->GetNumPlanes(mpHwBuffer);
int ret = 0;
if (planeNum == 1) {
void* data = nullptr;
ret = (mImgFormat == HAL_PIXEL_FORMAT_BLOB)
? mGbmBufferManager->Lock(mpHwBuffer, 0, 0, 0,
mImgSize.w * mImgSize.h, 1, &data)
: mGbmBufferManager->Lock(mpHwBuffer, 0, 0, 0, mImgSize.w,
mImgSize.h, &data);
if (ret) {
MY_LOGE("@%s: call Lock fail, mHandle:%p", __FUNCTION__, mpHwBuffer);
return MFALSE;
}
//
MINTPTR va = reinterpret_cast<MINTPTR>(data);
for (size_t i = 0; i < mvBufInfo.size(); i++) {
rvBufInfo[i]->va = va;
va += mvBufInfo[i]->sizeInBytes;
}
} else if (planeNum > 1) {
struct android_ycbcr ycbrData;
ret = mGbmBufferManager->LockYCbCr(mpHwBuffer, 0, 0, 0, mImgSize.w,
mImgSize.h, &ycbrData);
if (ret) {
MY_LOGE("@%s: call LockYCbCr fail, mHandle:%p", __FUNCTION__, mpHwBuffer);
return MFALSE;
}
rvBufInfo[0]->va = reinterpret_cast<MINTPTR>(ycbrData.y);
if (planeNum == 2) {
switch (v4l2Fmt) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
rvBufInfo[1]->va = reinterpret_cast<MINTPTR>(ycbrData.cb);
break;
default:
MY_LOGE("Unsupported semi-planar format: %s",
FormatToString(v4l2Fmt).c_str());
}
} else { // num_planes == 3
switch (v4l2Fmt) {
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YVU420M:
rvBufInfo[1]->va = reinterpret_cast<MINTPTR>(ycbrData.cr);
rvBufInfo[2]->va = reinterpret_cast<MINTPTR>(ycbrData.cb);
break;
default:
MY_LOGE("Unsupported planar format: %s",
FormatToString(v4l2Fmt).c_str());
}
}
} else {
MY_LOGE("ERROR @%s: planeNum is 0", __FUNCTION__);
return MFALSE;
}
//
return MTRUE;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
GbmImageBufferHeap::impUnlockBuf(char const* szCallerName,
MINT usage,
BufInfoVect_t const& rvBufInfo) {
for (MUINT32 i = 0; i < rvBufInfo.size(); i++) {
std::shared_ptr<BufInfo> pBufInfo = rvBufInfo[i];
// SW Access.
if (0 != pBufInfo->va) {
pBufInfo->va = 0;
} else {
MY_LOGD("%s@ skip VA=0 at %d-th plane", szCallerName, i);
}
}
int ret = mGbmBufferManager->Unlock(mpHwBuffer);
if (ret) {
MY_LOGE("@%s: call Unlock fail, mHandle:%p, ret:%d", __FUNCTION__,
mpHwBuffer, ret);
return false;
}
return true;
}
/******************************************************************************
*
******************************************************************************/