Loading include/gui/CpuConsumer.h +6 −47 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ #ifndef ANDROID_GUI_CPUCONSUMER_H #define ANDROID_GUI_CPUCONSUMER_H #include <gui/BufferQueue.h> #include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> Loading @@ -37,19 +37,10 @@ namespace android { * This queue is synchronous by default. */ class CpuConsumer: public virtual RefBase, protected BufferQueue::ConsumerListener class CpuConsumer: public ConsumerBase { public: struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called each time an additional frame becomes // available for consumption. A new frame queued will always trigger the // callback, whether the queue is empty or not. // // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onFrameAvailable() = 0; }; typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; struct LockedBuffer { uint8_t *data; Loading @@ -68,8 +59,6 @@ class CpuConsumer: public virtual RefBase, // how many buffers can be locked for user access at the same time. CpuConsumer(uint32_t maxLockedBuffers); virtual ~CpuConsumer(); // set the name of the CpuConsumer that will be used to identify it in // log messages. void setName(const String8& name); Loading @@ -91,50 +80,20 @@ class CpuConsumer: public virtual RefBase, // lockNextBuffer. status_t unlockBuffer(const LockedBuffer &nativeBuffer); // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; } protected: // Implementation of the BufferQueue::ConsumerListener interface. These // calls are used to notify the CpuConsumer of asynchronous events in the // BufferQueue. virtual void onFrameAvailable(); virtual void onBuffersReleased(); sp<ISurfaceTexture> getProducerInterface() const { return getBufferQueue(); } private: // Free local buffer state status_t freeBufferLocked(int buf); // Maximum number of buffers that can be locked at a time uint32_t mMaxLockedBuffers; // mName is a string used to identify the SurfaceTexture in log messages. // It can be set by the setName method. String8 mName; // mFrameAvailableListener is the listener object that will be called when a // new frame becomes available. If it is not NULL it will be called from // queueBuffer. sp<FrameAvailableListener> mFrameAvailableListener; // Underlying buffer queue sp<BufferQueue> mBufferQueue; void freeBufferLocked(int slotIndex); // Array for caching buffers from the buffer queue sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS]; // Array for tracking pointers passed to the consumer, matching the // mBufferSlot indexing // mSlots indexing void *mBufferPointers[BufferQueue::NUM_BUFFER_SLOTS]; // Count of currently locked buffers uint32_t mCurrentLockedBuffers; // mMutex is the mutex used to prevent concurrent access to the member // variables of CpuConsumer objects. It must be locked whenever the // member variables are accessed. mutable Mutex mMutex; }; } // namespace android Loading libs/gui/CpuConsumer.cpp +26 −113 Original line number Diff line number Diff line Loading @@ -29,49 +29,18 @@ 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) : ConsumerBase(new BufferQueue(true, 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) { Loading @@ -92,7 +61,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { Mutex::Autolock _l(mMutex); err = mBufferQueue->acquireBuffer(&b); err = acquireBufferLocked(&b); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { return BAD_VALUE; Loading @@ -104,16 +73,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { 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) { Loading @@ -123,7 +82,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } err = mBufferSlot[buf]->lock( err = mSlots[buf].mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &mBufferPointers[buf]); Loading @@ -135,10 +94,10 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } 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->width = mSlots[buf].mGraphicBuffer->getWidth(); nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight(); nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat(); nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; Loading @@ -153,90 +112,44 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); int buf = 0; int slotIndex = 0; status_t err; void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { if (bufPtr == mBufferPointers[buf]) break; for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) { if (bufPtr == mBufferPointers[slotIndex]) break; } if (buf == BufferQueue::NUM_BUFFER_SLOTS) { if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } mBufferPointers[buf] = NULL; err = mBufferSlot[buf]->unlock(); mBufferPointers[slotIndex] = NULL; err = mSlots[slotIndex].mGraphicBuffer->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); CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex); return err; } releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 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(); void CpuConsumer::freeBufferLocked(int slotIndex) { if (mBufferPointers[slotIndex] != NULL) { status_t err; CC_LOGW("Buffer %d freed while locked by consumer", slotIndex); mBufferPointers[slotIndex] = NULL; err = mSlots[slotIndex].mGraphicBuffer->unlock(); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex); } mCurrentLockedBuffers--; } mBufferSlot[buf] = NULL; return err; ConsumerBase::freeBufferLocked(slotIndex); } } // namespace android Loading
include/gui/CpuConsumer.h +6 −47 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ #ifndef ANDROID_GUI_CPUCONSUMER_H #define ANDROID_GUI_CPUCONSUMER_H #include <gui/BufferQueue.h> #include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> Loading @@ -37,19 +37,10 @@ namespace android { * This queue is synchronous by default. */ class CpuConsumer: public virtual RefBase, protected BufferQueue::ConsumerListener class CpuConsumer: public ConsumerBase { public: struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called each time an additional frame becomes // available for consumption. A new frame queued will always trigger the // callback, whether the queue is empty or not. // // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onFrameAvailable() = 0; }; typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; struct LockedBuffer { uint8_t *data; Loading @@ -68,8 +59,6 @@ class CpuConsumer: public virtual RefBase, // how many buffers can be locked for user access at the same time. CpuConsumer(uint32_t maxLockedBuffers); virtual ~CpuConsumer(); // set the name of the CpuConsumer that will be used to identify it in // log messages. void setName(const String8& name); Loading @@ -91,50 +80,20 @@ class CpuConsumer: public virtual RefBase, // lockNextBuffer. status_t unlockBuffer(const LockedBuffer &nativeBuffer); // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; } protected: // Implementation of the BufferQueue::ConsumerListener interface. These // calls are used to notify the CpuConsumer of asynchronous events in the // BufferQueue. virtual void onFrameAvailable(); virtual void onBuffersReleased(); sp<ISurfaceTexture> getProducerInterface() const { return getBufferQueue(); } private: // Free local buffer state status_t freeBufferLocked(int buf); // Maximum number of buffers that can be locked at a time uint32_t mMaxLockedBuffers; // mName is a string used to identify the SurfaceTexture in log messages. // It can be set by the setName method. String8 mName; // mFrameAvailableListener is the listener object that will be called when a // new frame becomes available. If it is not NULL it will be called from // queueBuffer. sp<FrameAvailableListener> mFrameAvailableListener; // Underlying buffer queue sp<BufferQueue> mBufferQueue; void freeBufferLocked(int slotIndex); // Array for caching buffers from the buffer queue sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS]; // Array for tracking pointers passed to the consumer, matching the // mBufferSlot indexing // mSlots indexing void *mBufferPointers[BufferQueue::NUM_BUFFER_SLOTS]; // Count of currently locked buffers uint32_t mCurrentLockedBuffers; // mMutex is the mutex used to prevent concurrent access to the member // variables of CpuConsumer objects. It must be locked whenever the // member variables are accessed. mutable Mutex mMutex; }; } // namespace android Loading
libs/gui/CpuConsumer.cpp +26 −113 Original line number Diff line number Diff line Loading @@ -29,49 +29,18 @@ 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) : ConsumerBase(new BufferQueue(true, 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) { Loading @@ -92,7 +61,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { Mutex::Autolock _l(mMutex); err = mBufferQueue->acquireBuffer(&b); err = acquireBufferLocked(&b); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { return BAD_VALUE; Loading @@ -104,16 +73,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { 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) { Loading @@ -123,7 +82,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } err = mBufferSlot[buf]->lock( err = mSlots[buf].mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &mBufferPointers[buf]); Loading @@ -135,10 +94,10 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } 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->width = mSlots[buf].mGraphicBuffer->getWidth(); nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight(); nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat(); nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; Loading @@ -153,90 +112,44 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); int buf = 0; int slotIndex = 0; status_t err; void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { if (bufPtr == mBufferPointers[buf]) break; for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) { if (bufPtr == mBufferPointers[slotIndex]) break; } if (buf == BufferQueue::NUM_BUFFER_SLOTS) { if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } mBufferPointers[buf] = NULL; err = mBufferSlot[buf]->unlock(); mBufferPointers[slotIndex] = NULL; err = mSlots[slotIndex].mGraphicBuffer->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); CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex); return err; } releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 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(); void CpuConsumer::freeBufferLocked(int slotIndex) { if (mBufferPointers[slotIndex] != NULL) { status_t err; CC_LOGW("Buffer %d freed while locked by consumer", slotIndex); mBufferPointers[slotIndex] = NULL; err = mSlots[slotIndex].mGraphicBuffer->unlock(); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex); } mCurrentLockedBuffers--; } mBufferSlot[buf] = NULL; return err; ConsumerBase::freeBufferLocked(slotIndex); } } // namespace android