/* // 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