surfaceflinger: refactor FrambufferSurface

This change refactors the FramebufferSurface class to inherit from the new
ConsumerBase class.

Bug: 6620200
Change-Id: I46ec942ddb019658e3c5e79465548b171b2261f2
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 7006957..3aa3a50 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_SRC_FILES:= \
 	BitTube.cpp \
 	BufferQueue.cpp \
+	ConsumerBase.cpp \
 	DisplayEventReceiver.cpp \
 	IDisplayEventConnection.cpp \
 	ISensorEventConnection.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 23e3a4f..697635b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -85,7 +85,6 @@
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
-    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
     mMinUndequeuedBuffers(bufferCount),
     mMinAsyncBufferSlots(bufferCount + 1),
     mMinSyncBufferSlots(bufferCount),
@@ -98,7 +97,7 @@
     mAbandoned(false),
     mFrameCounter(0),
     mBufferHasBeenQueued(false),
-    mDefaultBufferFormat(0),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mConsumerUsageBits(0),
     mTransformHint(0)
 {
@@ -125,7 +124,8 @@
     if (bufferCount > NUM_BUFFER_SLOTS)
         return BAD_VALUE;
 
-    // special-case, nothing to do
+    mServerBufferCount = bufferCount;
+
     if (bufferCount == mBufferCount)
         return OK;
 
@@ -133,7 +133,6 @@
         bufferCount >= mBufferCount) {
         // easy, we just have more buffers
         mBufferCount = bufferCount;
-        mServerBufferCount = bufferCount;
         mDequeueCondition.broadcast();
     } else {
         // we're here because we're either
@@ -150,7 +149,6 @@
         // own one. the actual resizing will happen during the next
         // dequeueBuffer.
 
-        mServerBufferCount = bufferCount;
         mDequeueCondition.broadcast();
     }
     return OK;
@@ -260,7 +258,7 @@
         value = mDefaultHeight;
         break;
     case NATIVE_WINDOW_FORMAT:
-        value = mPixelFormat;
+        value = mDefaultBufferFormat;
         break;
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         value = mSynchronousMode ?
@@ -447,12 +445,6 @@
             h = mDefaultHeight;
         }
 
-        const bool updateFormat = (format != 0);
-        if (!updateFormat) {
-            // keep the current (or default) format
-            format = mPixelFormat;
-        }
-
         // buffer is now in DEQUEUED (but can also be current at the same time,
         // if we're in synchronous mode)
         mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
@@ -473,9 +465,6 @@
                         "failed");
                 return error;
             }
-            if (updateFormat) {
-                mPixelFormat = format;
-            }
 
             mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = graphicBuffer;
@@ -791,9 +780,9 @@
 
     snprintf(buffer, SIZE,
             "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
-            "mPixelFormat=%d, FIFO(%d)={%s}\n",
+            "default-format=%d, FIFO(%d)={%s}\n",
             prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
-            mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
+            mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
     result.append(buffer);
 
 
@@ -835,21 +824,22 @@
     }
 }
 
-void BufferQueue::freeBufferLocked(int i) {
-    mSlots[i].mGraphicBuffer = 0;
-    if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
-        mSlots[i].mNeedsCleanupOnRelease = true;
+void BufferQueue::freeBufferLocked(int slot) {
+    ST_LOGV("freeBufferLocked: slot=%d", slot);
+    mSlots[slot].mGraphicBuffer = 0;
+    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[slot].mNeedsCleanupOnRelease = true;
     }
-    mSlots[i].mBufferState = BufferSlot::FREE;
-    mSlots[i].mFrameNumber = 0;
-    mSlots[i].mAcquireCalled = false;
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mAcquireCalled = false;
 
     // destroy fence as BufferQueue now takes ownership
-    if (mSlots[i].mEglFence != EGL_NO_SYNC_KHR) {
-        eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mEglFence);
-        mSlots[i].mEglFence = EGL_NO_SYNC_KHR;
+    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
     }
-    mSlots[i].mFence.clear();
+    mSlots[slot].mFence.clear();
 }
 
 void BufferQueue::freeAllBuffersLocked() {
@@ -886,12 +876,14 @@
         buffer->mTimestamp = mSlots[buf].mTimestamp;
         buffer->mBuf = buf;
         buffer->mFence = mSlots[buf].mFence;
-        mSlots[buf].mAcquireCalled = true;
 
+        mSlots[buf].mAcquireCalled = true;
+        mSlots[buf].mNeedsCleanupOnRelease = false;
         mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[buf].mFence.clear();
+
         mQueue.erase(front);
         mDequeueCondition.broadcast();
-        mSlots[buf].mFence.clear();
 
         ATRACE_INT(mConsumerName.string(), mQueue.size());
     } else {
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
new file mode 100644
index 0000000..af19ac0
--- /dev/null
+++ b/libs/gui/ConsumerBase.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2010 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_TAG "ConsumerBase"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <hardware/hardware.h>
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ConsumerBase.h>
+
+#include <private/gui/ComposerService.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+// Macros for including the ConsumerBase name in log messages
+#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_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);
+}
+
+ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
+	mBufferQueue(bufferQueue) {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    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) {
+        CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
+                strerror(-err), err);
+    } else {
+        mBufferQueue->setConsumerName(mName);
+    }
+}
+
+ConsumerBase::~ConsumerBase() {
+	CB_LOGV("~ConsumerBase");
+    abandon();
+}
+
+void ConsumerBase::freeBufferLocked(int slotIndex) {
+    CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mFence = 0;
+}
+
+// Used for refactoring, should not be in final interface
+sp<BufferQueue> ConsumerBase::getBufferQueue() const {
+    Mutex::Autolock lock(mMutex);
+    return mBufferQueue;
+}
+
+void ConsumerBase::onFrameAvailable() {
+    CB_LOGV("onFrameAvailable");
+
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener;
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+void ConsumerBase::onBuffersReleased() {
+    Mutex::Autolock lock(mMutex);
+
+    CB_LOGV("onBuffersReleased");
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
+    uint32_t mask = 0;
+    mBufferQueue->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1 << i)) {
+            freeBufferLocked(i);
+        }
+    }
+}
+
+void ConsumerBase::abandon() {
+    CB_LOGV("abandon");
+    Mutex::Autolock lock(mMutex);
+
+    if (!mAbandoned) {
+        abandonLocked();
+        mAbandoned = true;
+    }
+}
+
+void ConsumerBase::abandonLocked() {
+	CB_LOGV("abandonLocked");
+    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+    // disconnect from the BufferQueue
+    mBufferQueue->consumerDisconnect();
+    mBufferQueue.clear();
+}
+
+void ConsumerBase::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    CB_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+void ConsumerBase::dump(String8& result) const {
+    char buffer[1024];
+    dump(result, "", buffer, 1024);
+}
+
+void ConsumerBase::dump(String8& result, const char* prefix,
+        char* buffer, size_t size) const {
+    Mutex::Autolock _l(mMutex);
+    dumpLocked(result, prefix, buffer, size);
+}
+
+void ConsumerBase::dumpLocked(String8& result, const char* prefix,
+        char* buffer, size_t SIZE) const {
+    snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned));
+    result.append(buffer);
+
+    if (!mAbandoned) {
+        mBufferQueue->dump(result, prefix, buffer, SIZE);
+    }
+}
+
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
+    status_t err = mBufferQueue->acquireBuffer(item);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (item->mGraphicBuffer != NULL) {
+        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+    }
+
+    CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
+
+    return OK;
+}
+
+status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
+       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+    CB_LOGV("releaseBufferLocked: slot=%d", slot);
+    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
+    if (err == BufferQueue::STALE_BUFFER_SLOT) {
+        freeBufferLocked(slot);
+    }
+
+    mSlots[slot].mFence.clear();
+
+    return err;
+}
+
+} // namespace android
\ No newline at end of file