/*
// Copyright (c) 2014 Intel Corporation
//
// 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.
*/
#include <HwcTrace.h>
#include <hardware/hwcomposer.h>
#include <BufferManager.h>
#include <hal_public.h>
#include <DrmConfig.h>
namespace android {
namespace intel {
BufferManager::BufferManager()
: mGralloc(NULL),
mFrameBuffers(),
mBufferPool(NULL),
mDataBuffer(NULL),
mDataBufferLock(),
mInitialized(false)
{
CTRACE();
}
BufferManager::~BufferManager()
{
WARN_IF_NOT_DEINIT();
}
bool BufferManager::initCheck() const
{
return mInitialized;
}
bool BufferManager::initialize()
{
CTRACE();
// create buffer pool
mBufferPool = new BufferCache(DEFAULT_BUFFER_POOL_SIZE);
if (!mBufferPool) {
ETRACE("failed to create gralloc buffer cache");
return false;
}
// init gralloc module
if (gralloc_open_img(&mGralloc)) {
DEINIT_AND_RETURN_FALSE("failed to get gralloc module");
}
// create a dummy data buffer
mDataBuffer = createDataBuffer(0);
if (!mDataBuffer) {
DEINIT_AND_RETURN_FALSE("failed to create data buffer");
}
mInitialized = true;
return true;
}
void BufferManager::deinitialize()
{
mInitialized = false;
if (mBufferPool) {
// unmap & delete all cached buffer mappers
for (size_t i = 0; i < mBufferPool->getCacheSize(); i++) {
BufferMapper *mapper = mBufferPool->getMapper(i);
mapper->unmap();
delete mapper;
}
delete mBufferPool;
mBufferPool = NULL;
}
for (size_t j = 0; j < mFrameBuffers.size(); j++) {
BufferMapper *mapper = mFrameBuffers.valueAt(j);
mapper->unmap();
delete mapper;
}
mFrameBuffers.clear();
if (mGralloc) {
gralloc_close_img(mGralloc);
mGralloc = NULL;
}
if (mDataBuffer) {
delete mDataBuffer;
mDataBuffer = NULL;
}
}
void BufferManager::dump(Dump& d)
{
d.append("Buffer Manager status: pool size %d\n", mBufferPool->getCacheSize());
d.append("-------------------------------------------------------------\n");
for (uint32_t i = 0; i < mBufferPool->getCacheSize(); i++) {
BufferMapper *mapper = mBufferPool->getMapper(i);
d.append("Buffer %d: handle %#x, (%dx%d), format %d, refCount %d\n",
i,
mapper->getHandle(),
mapper->getWidth(),
mapper->getHeight(),
mapper->getFormat(),
mapper->getRef());
}
return;
}
DataBuffer* BufferManager::lockDataBuffer(buffer_handle_t handle)
{
mDataBufferLock.lock();
mDataBuffer->resetBuffer(handle);
return mDataBuffer;
}
void BufferManager::unlockDataBuffer(DataBuffer *buffer)
{
mDataBufferLock.unlock();
}
DataBuffer* BufferManager::get(buffer_handle_t handle)
{
return createDataBuffer(handle);
}
void BufferManager::put(DataBuffer *buffer)
{
delete buffer;
}
BufferMapper* BufferManager::map(DataBuffer& buffer)
{
bool ret;
BufferMapper* mapper;
CTRACE();
Mutex::Autolock _l(mLock);
//try to get mapper from pool
mapper = mBufferPool->getMapper(buffer.getKey());
if (mapper) {
// increase mapper ref count
mapper->incRef();
return mapper;
}
// create a new buffer mapper and add it to pool
do {
VTRACE("new buffer, will add it");
mapper = createBufferMapper(buffer);
if (!mapper) {
ETRACE("failed to allocate mapper");
break;
}
ret = mapper->map();
if (!ret) {
ETRACE("failed to map");
delete mapper;
mapper = NULL;
break;
}
ret = mBufferPool->addMapper(buffer.getKey(), mapper);
if (!ret) {
ETRACE("failed to add mapper");
break;
}
// increase mapper ref count
mapper->incRef();
return mapper;
} while (0);
// error handling
if (mapper) {
mapper->unmap();
delete mapper;
}
return NULL;
}
void BufferManager::unmap(BufferMapper *mapper)
{
Mutex::Autolock _l(mLock);
if (!mapper) {
ETRACE("invalid mapper");
return;
}
// unmap & remove this mapper from buffer when refCount = 0
int refCount = mapper->decRef();
if (refCount < 0) {
ETRACE("invalid ref count");
} else if (!refCount) {
// remove mapper from buffer pool
mBufferPool->removeMapper(mapper);
mapper->unmap();
delete mapper;
}
}
buffer_handle_t BufferManager::allocFrameBuffer(int width, int height, int *stride)
{
RETURN_NULL_IF_NOT_INIT();
if (!mGralloc) {
WTRACE("Alloc device is not available");
return 0;
}
if (!width || !height || !stride) {
ETRACE("invalid input parameter");
return 0;
}
ITRACE("size of frame buffer to create: %dx%d", width, height);
buffer_handle_t handle = 0;
status_t err = gralloc_device_alloc_img(
mGralloc,
width,
height,
DrmConfig::getFrameBufferFormat(),
0, // GRALLOC_USAGE_HW_FB
&handle,
stride);
if (err != 0) {
ETRACE("failed to allocate frame buffer, error = %d", err);
return 0;
}
DataBuffer *buffer = NULL;
BufferMapper *mapper = NULL;
do {
buffer = lockDataBuffer(handle);
if (!buffer) {
ETRACE("failed to get data buffer, handle = %p", handle);
break;
}
mapper = createBufferMapper(*buffer);
if (!mapper) {
ETRACE("failed to create buffer mapper");
break;
}
buffer_handle_t fbHandle;
if (!(fbHandle = mapper->getFbHandle(0))) {
ETRACE("failed to get Fb handle");
break;
}
mFrameBuffers.add(fbHandle, mapper);
unlockDataBuffer(buffer);
return fbHandle;
} while (0);
// error handling, release all allocated resources
if (buffer) {
unlockDataBuffer(buffer);
}
if (mapper) {
delete mapper;
}
gralloc_device_free_img(mGralloc, handle);
return 0;
}
void BufferManager::freeFrameBuffer(buffer_handle_t fbHandle)
{
RETURN_VOID_IF_NOT_INIT();
if (!mGralloc) {
WTRACE("Alloc device is not available");
return;
}
ssize_t index = mFrameBuffers.indexOfKey(fbHandle);
if (index < 0) {
ETRACE("invalid kernel handle");
return;
}
BufferMapper *mapper = mFrameBuffers.valueAt(index);
buffer_handle_t handle = mapper->getHandle();
mapper->putFbHandle();
delete mapper;
mFrameBuffers.removeItem(fbHandle);
gralloc_device_free_img(mGralloc, handle);
}
buffer_handle_t BufferManager::allocGrallocBuffer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage)
{
RETURN_NULL_IF_NOT_INIT();
if (!mGralloc) {
WTRACE("Alloc device is not available");
return 0;
}
if (!width || !height) {
ETRACE("invalid input parameter");
return 0;
}
ITRACE("size of graphic buffer to create: %dx%d", width, height);
buffer_handle_t handle = 0;
int stride;
status_t err = gralloc_device_alloc_img(
mGralloc,
width,
height,
format,
usage,
&handle,
&stride);
if (err != 0) {
ETRACE("failed to allocate gralloc buffer, error = %d", err);
return 0;
}
return handle;
}
void BufferManager::freeGrallocBuffer(buffer_handle_t handle)
{
RETURN_VOID_IF_NOT_INIT();
if (!mGralloc) {
WTRACE("Alloc device is not available");
return;
}
if (handle)
gralloc_device_free_img(mGralloc, handle);
}
} // namespace intel
} // namespace android