OSDN Git Service

SurfaceTexture: inherit from ConsumerBase
authorJamie Gennis <jgennis@google.com>
Wed, 8 Aug 2012 01:03:04 +0000 (18:03 -0700)
committerJamie Gennis <jgennis@google.com>
Fri, 17 Aug 2012 01:11:02 +0000 (18:11 -0700)
This change makes SurfaceTexture inherit from ConsumerBase.  It removes all of
the functionality from SurfaceTexture that is now provided by the base class.

Change-Id: I4a881df42810a14ee32d4ef7c8772a8f2510f4c7

include/gui/ConsumerBase.h
include/gui/SurfaceTexture.h
libs/gui/ConsumerBase.cpp
libs/gui/SurfaceTexture.cpp

index d2bf0f6..1f643a3 100644 (file)
@@ -189,14 +189,6 @@ protected:
     // if none is supplied
     sp<BufferQueue> mBufferQueue;
 
-    // mAttached indicates whether the ConsumerBase is currently attached to
-    // an OpenGL ES context.  For legacy reasons, this is initialized to true,
-    // indicating that the ConsumerBase is considered to be attached to
-    // whatever context is current at the time of the first updateTexImage call.
-    // It is set to false by detachFromContext, and then set to true again by
-    // attachToContext.
-    bool mAttached;
-
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of ConsumerBase objects. It must be locked whenever the
     // member variables are accessed.
index 66c390a..0a83ce6 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <gui/ISurfaceTexture.h>
 #include <gui/BufferQueue.h>
+#include <gui/ConsumerBase.h>
 
 #include <ui/GraphicBuffer.h>
 
@@ -39,20 +40,9 @@ namespace android {
 
 class String8;
 
-class SurfaceTexture : public virtual RefBase,
-        protected BufferQueue::ConsumerListener {
+class SurfaceTexture : public ConsumerBase {
 public:
-    struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called each time an additional frame becomes
-        // available for consumption. This means that frames that are queued
-        // while in asynchronous mode only trigger the callback if no previous
-        // frames are pending. Frames queued while in synchronous mode always
-        // trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onFrameAvailable() = 0;
-    };
+    typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
 
     // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
     // name of the OpenGL ES texture to which images are to be streamed.
@@ -82,8 +72,6 @@ public:
             GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
             const sp<BufferQueue> &bufferQueue = 0);
 
-    virtual ~SurfaceTexture();
-
     // updateTexImage sets the image contents of the target texture to that of
     // the most recently queued buffer.
     //
@@ -132,16 +120,6 @@ public:
     // documented by the source.
     int64_t getTimestamp();
 
-    // setFrameAvailableListener sets the listener object that will be notified
-    // when a new frame becomes available.
-    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
-
-    // getAllocator retrieves the binder object that must be referenced as long
-    // as the GraphicBuffers dequeued from this SurfaceTexture are referenced.
-    // Holding this binder reference prevents SurfaceFlinger from freeing the
-    // buffers before the client is done with them.
-    sp<IBinder> getAllocator();
-
     // setDefaultBufferSize is used to set the size of buffers returned by
     // requestBuffers when a with and height of zero is requested.
     // A call to setDefaultBufferSize() may trigger requestBuffers() to
@@ -180,17 +158,6 @@ public:
     // synchronous mode.
     bool isSynchronousMode() const;
 
-    // abandon frees all the buffers and puts the SurfaceTexture into the
-    // 'abandoned' state.  Once put in this state the SurfaceTexture can never
-    // leave it.  When in the 'abandoned' state, all methods of the
-    // ISurfaceTexture interface will fail with the NO_INIT error.
-    //
-    // Note that while calling this method causes all the buffers to be freed
-    // from the perspective of the the SurfaceTexture, if there are additional
-    // references on the buffers (e.g. if a buffer is referenced by a client or
-    // by OpenGL ES as a texture) then those buffer will remain allocated.
-    void abandon();
-
     // set the name of the SurfaceTexture that will be used to identify it in
     // log messages.
     void setName(const String8& name);
@@ -204,7 +171,9 @@ public:
 
     // getBufferQueue returns the BufferQueue object to which this
     // SurfaceTexture is connected.
-    sp<BufferQueue> getBufferQueue() const;
+    sp<BufferQueue> getBufferQueue() const {
+        return mBufferQueue;
+    }
 
     // detachFromContext detaches the SurfaceTexture from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
@@ -233,17 +202,25 @@ public:
     // current at the time of the last call to detachFromContext.
     status_t attachToContext(GLuint tex);
 
-    // dump our state in a String
-    virtual void dump(String8& result) const;
-    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
-
 protected:
 
-    // Implementation of the BufferQueue::ConsumerListener interface.  These
-    // calls are used to notify the SurfaceTexture of asynchronous events in the
-    // BufferQueue.
-    virtual void onFrameAvailable();
-    virtual void onBuffersReleased();
+    // abandonLocked overrides the ConsumerBase method to clear
+    // mCurrentTextureBuf in addition to the ConsumerBase behavior.
+    virtual void abandonLocked();
+
+    // dumpLocked overrides the ConsumerBase method to dump SurfaceTexture-
+    // specific info in addition to the ConsumerBase behavior.
+    virtual void dumpLocked(String8& result, const char* prefix, char* buffer,
+           size_t size) const;
+
+    // acquireBufferLocked overrides the ConsumerBase method to update the
+    // mEglSlots array in addition to the ConsumerBase behavior.
+    virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+
+    // releaseBufferLocked overrides the ConsumerBase method to update the
+    // mEglSlots array in addition to the ConsumerBase.
+    virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
+           EGLSyncKHR eglFence, const sp<Fence>& fence);
 
     static bool isExternalFormat(uint32_t format);
 
@@ -351,11 +328,9 @@ private:
     struct EGLSlot {
         EGLSlot()
         : mEglImage(EGL_NO_IMAGE_KHR),
-          mFence(EGL_NO_SYNC_KHR) {
+          mEglFence(EGL_NO_SYNC_KHR) {
         }
 
-        sp<GraphicBuffer> mGraphicBuffer;
-
         // mEglImage is the EGLImage created from mGraphicBuffer.
         EGLImageKHR mEglImage;
 
@@ -363,14 +338,7 @@ private:
         // associated with this buffer slot may be dequeued. It is initialized
         // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
         // on a compile-time option) set to a new sync object in updateTexImage.
-        EGLSyncKHR mFence;
-
-        // mReleaseFence is a fence which will signal when the buffer
-        // associated with this buffer slot is no longer being used by the
-        // consumer and can be overwritten. The buffer can be dequeued before
-        // the fence signals; the producer is responsible for delaying writes
-        // until it signals.
-        sp<Fence> mReleaseFence;
+        EGLSyncKHR mEglFence;
     };
 
     // mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently
@@ -392,23 +360,7 @@ private:
     // slot that has not yet been used. The buffer allocated to a slot will also
     // be replaced if the requested buffer usage or geometry differs from that
     // of the buffer allocated to a slot.
-    EGLSlot mEGLSlots[BufferQueue::NUM_BUFFER_SLOTS];
-
-    // mAbandoned indicates that the BufferQueue will no longer be used to
-    // consume images buffers pushed to it using the ISurfaceTexture interface.
-    // It is initialized to false, and set to true in the abandon method.  A
-    // BufferQueue that has been abandoned will return the NO_INIT error from
-    // all ISurfaceTexture methods capable of returning an error.
-    bool mAbandoned;
-
-    // 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;
+    EGLSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
 
     // mCurrentTexture is the buffer slot index of the buffer that is currently
     // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
@@ -418,22 +370,13 @@ private:
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
-    // The SurfaceTexture has-a BufferQueue and is responsible for creating this object
-    // if none is supplied
-    sp<BufferQueue> mBufferQueue;
-
-    // mAttached indicates whether the SurfaceTexture is currently attached to
+    // mAttached indicates whether the ConsumerBase is currently attached to
     // an OpenGL ES context.  For legacy reasons, this is initialized to true,
-    // indicating that the SurfaceTexture is considered to be attached to
+    // indicating that the ConsumerBase is considered to be attached to
     // whatever context is current at the time of the first updateTexImage call.
     // It is set to false by detachFromContext, and then set to true again by
     // attachToContext.
     bool mAttached;
-
-    // mMutex is the mutex used to prevent concurrent access to the member
-    // variables of SurfaceTexture objects. It must be locked whenever the
-    // member variables are accessed.
-    mutable Mutex mMutex;
 };
 
 // ----------------------------------------------------------------------------
index af19ac0..17bbfd1 100644 (file)
@@ -53,7 +53,8 @@ static int32_t createProcessUniqueId() {
 }
 
 ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
-       mBufferQueue(bufferQueue) {
+        mAbandoned(false),
+        mBufferQueue(bufferQueue) {
     // Choose a name using the PID and a process-unique ID.
     mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
index 6666081..451ccc2 100644 (file)
@@ -26,6 +26,8 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <hardware/hardware.h>
+
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
@@ -96,14 +98,10 @@ static float mtxRot270[16] = {
 
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
-    static volatile int32_t globalCounter = 0;
-    return android_atomic_inc(&globalCounter);
-}
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
         GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
+    ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
     mCurrentTransform(0),
     mCurrentTimestamp(0),
     mFilteringEnabled(true),
@@ -116,47 +114,15 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
     mTexTarget(texTarget),
     mEglDisplay(EGL_NO_DISPLAY),
     mEglContext(EGL_NO_CONTEXT),
-    mAbandoned(false),
     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
     mAttached(true)
 {
-    // Choose a name using the PID and a process-unique ID.
-    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
     ST_LOGV("SurfaceTexture");
-    if (bufferQueue == 0) {
-        ST_LOGV("Creating a new BufferQueue");
-        mBufferQueue = new BufferQueue(allowSynchronousMode);
-    }
-    else {
-        mBufferQueue = bufferQueue;
-    }
 
     memcpy(mCurrentTransformMatrix, mtxIdentity,
             sizeof(mCurrentTransformMatrix));
 
-    // 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) {
-        ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
-                strerror(-err), err);
-    } else {
-        mBufferQueue->setConsumerName(mName);
-        mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
-    }
-}
-
-SurfaceTexture::~SurfaceTexture() {
-    ST_LOGV("~SurfaceTexture");
-
-    abandon();
+    mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
 }
 
 status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
@@ -177,6 +143,42 @@ status_t SurfaceTexture::updateTexImage() {
     return SurfaceTexture::updateTexImage(NULL);
 }
 
+status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
+    status_t err = ConsumerBase::acquireBufferLocked(item);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    int slot = item->mBuf;
+    if (item->mGraphicBuffer != NULL) {
+        if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage);
+            mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+        }
+    }
+
+    // Update the GL texture object. We may have to do this even when
+    // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
+    // detaching from a context but the buffer has not been re-allocated.
+    EGLImageKHR image = createImage(mEglDisplay, mSlots[slot].mGraphicBuffer);
+    if (image == EGL_NO_IMAGE_KHR) {
+        return UNKNOWN_ERROR;
+    }
+    mEglSlots[slot].mEglImage = image;
+
+    return NO_ERROR;
+}
+
+status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
+       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+    status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
+           eglFence, fence);
+
+    mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR;
+
+    return err;
+}
+
 status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
     ATRACE_CALL();
     ST_LOGV("updateTexImage");
@@ -217,97 +219,65 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
 
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    err = mBufferQueue->acquireBuffer(&item);
+    err = acquireBufferLocked(&item);
     if (err == NO_ERROR) {
         int buf = item.mBuf;
-        // This buffer was newly allocated, so we need to clean up on our side
-        if (item.mGraphicBuffer != NULL) {
-            mEGLSlots[buf].mGraphicBuffer = 0;
-            if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-                eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage);
-                mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-            }
-            mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
-        }
 
         // we call the rejecter here, in case the caller has a reason to
         // not accept this buffer. this is used by SurfaceFlinger to
         // reject buffers which have the wrong size
-        if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
-            mBufferQueue->releaseBuffer(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+        if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
             glBindTexture(mTexTarget, mTexName);
             return NO_ERROR;
         }
 
-        // Update the GL texture object. We may have to do this even when
-        // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
-        // detaching from a context but the buffer has not been re-allocated.
-        EGLImageKHR image = mEGLSlots[buf].mEglImage;
-        if (image == EGL_NO_IMAGE_KHR) {
-            if (mEGLSlots[buf].mGraphicBuffer == NULL) {
-                ST_LOGE("updateTexImage: buffer at slot %d is null", buf);
-                err = BAD_VALUE;
-            } else {
-                image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer);
-                mEGLSlots[buf].mEglImage = image;
-                if (image == EGL_NO_IMAGE_KHR) {
-                    // NOTE: if dpy was invalid, createImage() is guaranteed to
-                    // fail. so we'd end up here.
-                    err = UNKNOWN_ERROR;
-                }
-            }
+        GLint error;
+        while ((error = glGetError()) != GL_NO_ERROR) {
+            ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
         }
 
-        if (err == NO_ERROR) {
-            GLint error;
-            while ((error = glGetError()) != GL_NO_ERROR) {
-                ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
-            }
-
-            glBindTexture(mTexTarget, mTexName);
-            glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+        EGLImageKHR image = mEglSlots[buf].mEglImage;
+        glBindTexture(mTexTarget, mTexName);
+        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
 
-            while ((error = glGetError()) != GL_NO_ERROR) {
-                ST_LOGE("updateTexImage: error binding external texture image %p "
-                        "(slot %d): %#04x", image, buf, error);
-                err = UNKNOWN_ERROR;
-            }
+        while ((error = glGetError()) != GL_NO_ERROR) {
+            ST_LOGE("updateTexImage: error binding external texture image %p "
+                    "(slot %d): %#04x", image, buf, error);
+            err = UNKNOWN_ERROR;
+        }
 
-            if (err == NO_ERROR) {
-                err = syncForReleaseLocked(dpy);
-            }
+        if (err == NO_ERROR) {
+            err = syncForReleaseLocked(dpy);
         }
 
         if (err != NO_ERROR) {
             // Release the buffer we just acquired.  It's not safe to
             // release the old buffer, so instead we just drop the new frame.
-            mBufferQueue->releaseBuffer(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
             return err;
         }
 
         ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
                 mCurrentTexture,
                 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
-                buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
+                buf, mSlots[buf].mGraphicBuffer->handle);
 
         // release old buffer
         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-            status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
-                    mEGLSlots[mCurrentTexture].mFence,
-                    mEGLSlots[mCurrentTexture].mReleaseFence);
-            mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
-            mEGLSlots[mCurrentTexture].mReleaseFence.clear();
-            if (status == BufferQueue::STALE_BUFFER_SLOT) {
-                freeBufferLocked(mCurrentTexture);
-            } else if (status != NO_ERROR) {
-                ST_LOGE("updateTexImage: released invalid buffer");
+            status_t status = releaseBufferLocked(mCurrentTexture, dpy,
+                    mEglSlots[mCurrentTexture].mEglFence,
+                    mSlots[mCurrentTexture].mFence);
+            if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
+                ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
+                       strerror(-status), status);
                 err = status;
             }
         }
 
         // Update the SurfaceTexture state.
         mCurrentTexture = buf;
-        mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;
+        mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
         mCurrentCrop = item.mCrop;
         mCurrentTransform = item.mTransform;
         mCurrentScalingMode = item.mScalingMode;
@@ -330,20 +300,20 @@ void SurfaceTexture::setReleaseFence(int fenceFd) {
     sp<Fence> fence(new Fence(fenceFd));
     if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
         return;
-    if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
-        mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+    if (!mSlots[mCurrentTexture].mFence.get()) {
+        mSlots[mCurrentTexture].mFence = fence;
     } else {
         sp<Fence> mergedFence = Fence::merge(
                 String8("SurfaceTexture merged release"),
-                mEGLSlots[mCurrentTexture].mReleaseFence, fence);
+                mSlots[mCurrentTexture].mFence, fence);
         if (!mergedFence.get()) {
             ST_LOGE("failed to merge release fences");
             // synchronization is broken, the best we can do is hope fences
             // signal in order so the new fence will act like a union
-            mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+            mSlots[mCurrentTexture].mFence = fence;
             return;
         }
-        mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
+        mSlots[mCurrentTexture].mFence = mergedFence;
     }
 }
 
@@ -390,10 +360,10 @@ status_t SurfaceTexture::detachFromContext() {
     // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
     // new EGLDisplay).
     for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        EGLImageKHR img = mEGLSlots[i].mEglImage;
+        EGLImageKHR img = mEglSlots[i].mEglImage;
         if (img != EGL_NO_IMAGE_KHR) {
             eglDestroyImageKHR(mEglDisplay, img);
-            mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+            mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
         }
     }
 
@@ -481,7 +451,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
     ST_LOGV("syncForReleaseLocked");
 
     if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        EGLSyncKHR fence = mEGLSlots[mCurrentTexture].mFence;
+        EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
         if (fence != EGL_NO_SYNC_KHR) {
             // There is already a fence for the current slot.  We need to wait
             // on that before replacing it with another fence to ensure that all
@@ -509,7 +479,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
             return UNKNOWN_ERROR;
         }
         glFlush();
-        mEGLSlots[mCurrentTexture].mFence = fence;
+        mEglSlots[mCurrentTexture].mEglFence = fence;
     }
 
     return OK;
@@ -607,10 +577,12 @@ void SurfaceTexture::computeCurrentTransformMatrix() {
                     // only need to shrink by a half a pixel.
                     shrinkAmount = 0.5;
                     break;
+
                 default:
                     // If we don't recognize the format, we must assume the
                     // worst case (that we care about), which is YUV420.
                     shrinkAmount = 1.0;
+                    break;
             }
         }
 
@@ -650,13 +622,6 @@ nsecs_t SurfaceTexture::getTimestamp() {
     return mCurrentTimestamp;
 }
 
-void SurfaceTexture::setFrameAvailableListener(
-        const sp<FrameAvailableListener>& listener) {
-    ST_LOGV("setFrameAvailableListener");
-    Mutex::Autolock lock(mMutex);
-    mFrameAvailableListener = listener;
-}
-
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
         const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -736,35 +701,21 @@ bool SurfaceTexture::isSynchronousMode() const {
 
 void SurfaceTexture::freeBufferLocked(int slotIndex) {
     ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    mEGLSlots[slotIndex].mGraphicBuffer = 0;
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
     }
-    EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
+    EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
     if (img != EGL_NO_IMAGE_KHR) {
         ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
         eglDestroyImageKHR(mEglDisplay, img);
     }
-    mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+    mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
 }
 
-void SurfaceTexture::abandon() {
-    ST_LOGV("abandon");
-    Mutex::Autolock lock(mMutex);
-
-    if (!mAbandoned) {
-        mAbandoned = true;
-        mCurrentTextureBuf.clear();
-
-        // destroy all egl buffers
-        for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-            freeBufferLocked(i);
-        }
-
-        // disconnect from the BufferQueue
-        mBufferQueue->consumerDisconnect();
-        mBufferQueue.clear();
-    }
+void SurfaceTexture::abandonLocked() {
+    ST_LOGV("abandonLocked");
+    mCurrentTextureBuf.clear();
+    ConsumerBase::abandonLocked();
 }
 
 void SurfaceTexture::setName(const String8& name) {
@@ -796,71 +747,18 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
     return mBufferQueue->setSynchronousMode(enabled);
 }
 
-// Used for refactoring, should not be in final interface
-sp<BufferQueue> SurfaceTexture::getBufferQueue() const {
-    Mutex::Autolock lock(mMutex);
-    return mBufferQueue;
-}
-
-void SurfaceTexture::onFrameAvailable() {
-    ST_LOGV("onFrameAvailable");
-
-    sp<FrameAvailableListener> listener;
-    { // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        listener = mFrameAvailableListener;
-    }
-
-    if (listener != NULL) {
-        ST_LOGV("actually calling onFrameAvailable");
-        listener->onFrameAvailable();
-    }
-}
-
-void SurfaceTexture::onBuffersReleased() {
-    ST_LOGV("onBuffersReleased");
-
-    Mutex::Autolock lock(mMutex);
-
-    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 SurfaceTexture::dump(String8& result) const
-{
-    char buffer[1024];
-    dump(result, "", buffer, 1024);
-}
-
-void SurfaceTexture::dump(String8& result, const char* prefix,
-        char* buffer, size_t SIZE) const
+void SurfaceTexture::dumpLocked(String8& result, const char* prefix,
+        char* buffer, size_t size) const
 {
-    Mutex::Autolock _l(mMutex);
-    snprintf(buffer, SIZE, "%smTexName=%d, mAbandoned=%d\n", prefix, mTexName,
-            int(mAbandoned));
+    snprintf(buffer, size,
+       "%smTexName=%d mCurrentTexture=%d\n"
+       "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+       prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
+       mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
+       mCurrentTransform);
     result.append(buffer);
 
-    snprintf(buffer, SIZE,
-            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n",
-            prefix, mCurrentCrop.left,
-            mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-            mCurrentTransform, mCurrentTexture
-    );
-    result.append(buffer);
-
-    if (!mAbandoned) {
-        mBufferQueue->dump(result, prefix, buffer, SIZE);
-    }
+    ConsumerBase::dumpLocked(result, prefix, buffer, size);
 }
 
 static void mtxMul(float out[16], const float a[16], const float b[16]) {