summaryrefslogtreecommitdiff
path: root/libs/gui/BufferQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/BufferQueue.cpp')
-rw-r--r--libs/gui/BufferQueue.cpp158
1 files changed, 113 insertions, 45 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 0f9c7c5c4a..ffc5fa02a9 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -15,8 +15,8 @@
*/
#define LOG_TAG "BufferQueue"
-//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
@@ -146,13 +146,6 @@ void BufferQueue::setConsumerName(const String8& name) {
mConsumerName = name;
}
-void BufferQueue::setFrameAvailableListener(
- const sp<FrameAvailableListener>& listener) {
- ST_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = listener;
-}
-
status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
Mutex::Autolock lock(mMutex);
mDefaultBufferFormat = defaultFormat;
@@ -531,7 +524,7 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
- sp<FrameAvailableListener> listener;
+ sp<ConsumerListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
@@ -559,7 +552,7 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
// Synchronous mode always signals that an additional frame should
// be consumed.
- listener = mFrameAvailableListener;
+ listener = mConsumerListener;
} else {
// In asynchronous mode we only keep the most recent buffer.
if (mQueue.empty()) {
@@ -568,7 +561,7 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
// Asynchronous mode only signals that a frame should be
// consumed if no previous frame was pending. If a frame were
// pending then the consumer would have already been notified.
- listener = mFrameAvailableListener;
+ listener = mConsumerListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
@@ -682,6 +675,11 @@ status_t BufferQueue::connect(int api,
return NO_INIT;
}
+ if (mConsumerListener == NULL) {
+ ST_LOGE("connect: BufferQueue has no consumer!");
+ return NO_INIT;
+ }
+
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -712,38 +710,49 @@ status_t BufferQueue::connect(int api,
status_t BufferQueue::disconnect(int api) {
ATRACE_CALL();
ST_LOGV("disconnect: api=%d", api);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // it is not really an error to disconnect after the surface
- // has been abandoned, it should just be a no-op.
- return NO_ERROR;
- }
int err = NO_ERROR;
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- case NATIVE_WINDOW_API_CPU:
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- if (mConnectedApi == api) {
- drainQueueAndFreeBuffersLocked();
- mConnectedApi = NO_CONNECTED_API;
- mNextCrop.makeInvalid();
- mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
- mNextTransform = 0;
- mDequeueCondition.broadcast();
- } else {
- ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
- mConnectedApi, api);
+ sp<ConsumerListener> listener;
+
+ { // Scope for the lock
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ // it is not really an error to disconnect after the surface
+ // has been abandoned, it should just be a no-op.
+ return NO_ERROR;
+ }
+
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ if (mConnectedApi == api) {
+ drainQueueAndFreeBuffersLocked();
+ mConnectedApi = NO_CONNECTED_API;
+ mNextCrop.makeInvalid();
+ mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mNextTransform = 0;
+ mDequeueCondition.broadcast();
+ listener = mConsumerListener;
+ } else {
+ ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+ mConnectedApi, api);
+ err = -EINVAL;
+ }
+ break;
+ default:
+ ST_LOGE("disconnect: unknown API %d", api);
err = -EINVAL;
- }
- break;
- default:
- ST_LOGE("disconnect: unknown API %d", api);
- err = -EINVAL;
- break;
+ break;
+ }
}
+
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
return err;
}
@@ -841,7 +850,7 @@ void BufferQueue::freeAllBuffersLocked() {
}
}
-status_t BufferQueue::acquire(BufferItem *buffer) {
+status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
// check if queue is empty
@@ -855,8 +864,7 @@ status_t BufferQueue::acquire(BufferItem *buffer) {
if (mSlots[buf].mAcquireCalled) {
buffer->mGraphicBuffer = NULL;
- }
- else {
+ } else {
buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
}
buffer->mCrop = mSlots[buf].mCrop;
@@ -872,8 +880,7 @@ status_t BufferQueue::acquire(BufferItem *buffer) {
mDequeueCondition.broadcast();
ATRACE_INT(mConsumerName.string(), mQueue.size());
- }
- else {
+ } else {
// should be a better return code?
return -EINVAL;
}
@@ -907,17 +914,58 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
return OK;
}
+status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
+ ST_LOGV("consumerConnect");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+
+ mConsumerListener = consumerListener;
+
+ return OK;
+}
+
status_t BufferQueue::consumerDisconnect() {
+ ST_LOGV("consumerDisconnect");
Mutex::Autolock lock(mMutex);
- mAbandoned = true;
+ if (mConsumerListener == NULL) {
+ ST_LOGE("consumerDisconnect: No consumer is connected!");
+ return -EINVAL;
+ }
+ mAbandoned = true;
+ mConsumerListener = NULL;
mQueue.clear();
freeAllBuffersLocked();
mDequeueCondition.broadcast();
return OK;
}
+status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
+ ST_LOGV("getReleasedBuffers");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("getReleasedBuffers: BufferQueue has been abandoned!");
+ return NO_INIT;
+ }
+
+ uint32_t mask = 0;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (!mSlots[i].mAcquireCalled) {
+ mask |= 1 << i;
+ }
+ }
+ *slotMask = mask;
+
+ ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
+ return NO_ERROR;
+}
+
status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
{
ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
@@ -982,4 +1030,24 @@ status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
return err;
}
+BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
+ const wp<BufferQueue::ConsumerListener>& consumerListener):
+ mConsumerListener(consumerListener) {}
+
+BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
+
+void BufferQueue::ProxyConsumerListener::onFrameAvailable() {
+ sp<BufferQueue::ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onFrameAvailable();
+ }
+}
+
+void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
+ sp<BufferQueue::ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+}
+
}; // namespace android