diff options
Diffstat (limited to 'libs/gui/CpuConsumer.cpp')
-rw-r--r-- | libs/gui/CpuConsumer.cpp | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp new file mode 100644 index 0000000..513828c --- /dev/null +++ b/libs/gui/CpuConsumer.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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_NDEBUG 0 +#define LOG_TAG "CpuConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Log.h> + +#include <gui/CpuConsumer.h> + +#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +// Get an ID that's unique within this process. +static int32_t createProcessUniqueId() { + static volatile int32_t globalCounter = 0; + return android_atomic_inc(&globalCounter); +} + +CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) : + mMaxLockedBuffers(maxLockedBuffers), + mCurrentLockedBuffers(0) +{ + mName = String8::format("cc-unnamed-%d-%d", getpid(), + createProcessUniqueId()); + + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mBufferPointers[i] = NULL; + } + + mBufferQueue = new BufferQueue(true); + + wp<BufferQueue::ConsumerListener> listener; + sp<BufferQueue::ConsumerListener> proxy; + listener = static_cast<BufferQueue::ConsumerListener*>(this); + proxy = new BufferQueue::ProxyConsumerListener(listener); + + status_t err = mBufferQueue->consumerConnect(proxy); + if (err != NO_ERROR) { + ALOGE("CpuConsumer: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + } else { + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); + mBufferQueue->setConsumerName(mName); + } +} + +CpuConsumer::~CpuConsumer() +{ + Mutex::Autolock _l(mMutex); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + freeBufferLocked(i); + } + mBufferQueue->consumerDisconnect(); + mBufferQueue.clear(); +} + +void CpuConsumer::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + mName = name; + mBufferQueue->setConsumerName(name); +} + +status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { + status_t err; + + if (!nativeBuffer) return BAD_VALUE; + if (mCurrentLockedBuffers == mMaxLockedBuffers) { + return INVALID_OPERATION; + } + + BufferQueue::BufferItem b; + + Mutex::Autolock _l(mMutex); + + err = mBufferQueue->acquireBuffer(&b); + if (err != OK) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + return BAD_VALUE; + } else { + CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + return err; + } + } + + int buf = b.mBuf; + + if (b.mGraphicBuffer != NULL) { + if (mBufferPointers[buf] != NULL) { + CC_LOGE("Reallocation of buffer %d while in consumer use!", buf); + mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); + return BAD_VALUE; + } + mBufferSlot[buf] = b.mGraphicBuffer; + } + + if (b.mFence.get()) { + err = b.mFence->wait(Fence::TIMEOUT_NEVER); + if (err != OK) { + CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", + strerror(-err), err); + return err; + } + } + + err = mBufferSlot[buf]->lock( + GraphicBuffer::USAGE_SW_READ_OFTEN, + b.mCrop, + &mBufferPointers[buf]); + + if (mBufferPointers[buf] != NULL && err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), + err); + return err; + } + + nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]); + nativeBuffer->width = mBufferSlot[buf]->getWidth(); + nativeBuffer->height = mBufferSlot[buf]->getHeight(); + nativeBuffer->format = mBufferSlot[buf]->getPixelFormat(); + nativeBuffer->stride = mBufferSlot[buf]->getStride(); + + nativeBuffer->crop = b.mCrop; + nativeBuffer->transform = b.mTransform; + nativeBuffer->scalingMode = b.mScalingMode; + nativeBuffer->timestamp = b.mTimestamp; + nativeBuffer->frameNumber = b.mFrameNumber; + + mCurrentLockedBuffers++; + + return OK; +} + +status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { + Mutex::Autolock _l(mMutex); + int buf = 0; + status_t err; + + void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); + for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { + if (bufPtr == mBufferPointers[buf]) break; + } + if (buf == BufferQueue::NUM_BUFFER_SLOTS) { + CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); + return BAD_VALUE; + } + + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + return err; + } + err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); + if (err == BufferQueue::STALE_BUFFER_SLOT) { + freeBufferLocked(buf); + } else if (err != OK) { + CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__, + buf); + return err; + } + + mCurrentLockedBuffers--; + + return OK; +} + +void CpuConsumer::setFrameAvailableListener( + const sp<FrameAvailableListener>& listener) { + CC_LOGV("setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = listener; +} + + +void CpuConsumer::onFrameAvailable() { + CC_LOGV("onFrameAvailable"); + sp<FrameAvailableListener> listener; + { // scope for the lock + Mutex::Autolock _l(mMutex); + listener = mFrameAvailableListener; + } + + if (listener != NULL) { + CC_LOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +void CpuConsumer::onBuffersReleased() { + CC_LOGV("onBuffersReleased"); + + Mutex::Autolock lock(mMutex); + + uint32_t mask = 0; + mBufferQueue->getReleasedBuffers(&mask); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + if (mask & (1 << i)) { + freeBufferLocked(i); + } + } + +} + +status_t CpuConsumer::freeBufferLocked(int buf) { + status_t err = OK; + + if (mBufferPointers[buf] != NULL) { + CC_LOGW("Buffer %d freed while locked by consumer", buf); + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + } + mCurrentLockedBuffers--; + } + mBufferSlot[buf] = NULL; + return err; +} + +} // namespace android |