summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamie Gennis <jgennis@google.com>2012-08-24 11:11:06 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-08-24 11:11:07 -0700
commit490aee0fc5012acf2bf0b1dfe9c09e6fcca606fc (patch)
tree97fed915e84c3697091a9897fdb459f814071cfd
parent9b6a395e65ff88ab79fe92d6f112c434441ca606 (diff)
parent9fea3421ffddf6480f57f55a25936a886043d909 (diff)
downloadframeworks_native-490aee0fc5012acf2bf0b1dfe9c09e6fcca606fc.zip
frameworks_native-490aee0fc5012acf2bf0b1dfe9c09e6fcca606fc.tar.gz
frameworks_native-490aee0fc5012acf2bf0b1dfe9c09e6fcca606fc.tar.bz2
Merge "SurfaceTexture: inherit from ConsumerBase (try 2)" into jb-mr1-dev
-rw-r--r--include/gui/ConsumerBase.h77
-rw-r--r--include/gui/SurfaceTexture.h115
-rw-r--r--libs/gui/ConsumerBase.cpp3
-rw-r--r--libs/gui/SurfaceTexture.cpp287
4 files changed, 165 insertions, 317 deletions
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index d2bf0f6..a0ddca8 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -86,42 +86,25 @@ private:
protected:
- // TODO: Fix this comment
- // ConsumerBase constructs a new ConsumerBase object. tex indicates the
- // name of the OpenGL ES texture to which images are to be streamed.
- // allowSynchronousMode specifies whether or not synchronous mode can be
- // enabled. texTarget specifies the OpenGL ES texture target to which the
- // texture will be bound in updateTexImage. useFenceSync specifies whether
- // fences should be used to synchronize access to buffers if that behavior
- // is enabled at compile-time. A custom bufferQueue can be specified
- // if behavior for queue/dequeue/connect etc needs to be customized.
- // Otherwise a default BufferQueue will be created and used.
- //
- // For legacy reasons, the ConsumerBase is created in a state where it is
- // considered attached to an OpenGL ES context for the purposes of the
- // attachToContext and detachFromContext methods. However, despite being
- // considered "attached" to a context, the specific OpenGL ES context
- // doesn't get latched until the first call to updateTexImage. After that
- // point, all calls to updateTexImage must be made with the same OpenGL ES
- // context current.
- //
- // A ConsumerBase may be detached from one OpenGL ES context and then
- // attached to a different context using the detachFromContext and
- // attachToContext methods, respectively. The intention of these methods is
- // purely to allow a ConsumerBase to be transferred from one consumer
- // context to another. If such a transfer is not needed there is no
- // requirement that either of these methods be called.
+ // ConsumerBase constructs a new ConsumerBase object to consume image
+ // buffers from the given BufferQueue.
ConsumerBase(const sp<BufferQueue> &bufferQueue);
// Implementation of the BufferQueue::ConsumerListener interface. These
// calls are used to notify the ConsumerBase of asynchronous events in the
- // BufferQueue.
+ // BufferQueue. These methods should not need to be overridden by derived
+ // classes, but if they are overridden the ConsumerBase implementation
+ // must be called from the derived class.
virtual void onFrameAvailable();
virtual void onBuffersReleased();
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
- // slot and destroy the EGLImage in that slot. Otherwise it has no effect.
+ // slot. Otherwise it has no effect.
+ //
+ // Derived classes should override this method to clean up any state they
+ // keep per slot. If it is overridden, the derived class's implementation
+ // must call ConsumerBase::freeBufferLocked.
//
// This method must be called with mMutex locked.
virtual void freeBufferLocked(int slotIndex);
@@ -131,18 +114,43 @@ protected:
// abandon method should be overridden by child classes to add abandon-
// time behavior.
//
+ // Derived classes should override this method to clean up any object
+ // state they keep (as opposed to per-slot state). If it is overridden,
+ // the derived class's implementation must call ConsumerBase::abandonLocked.
+ //
// This method must be called with mMutex locked.
virtual void abandonLocked();
+ // dumpLocked dumps the current state of the ConsumerBase object to the
+ // result string. Each line is prefixed with the string pointed to by the
+ // prefix argument. The buffer argument points to a buffer that may be
+ // used for intermediate formatting data, and the size of that buffer is
+ // indicated by the size argument.
+ //
+ // Derived classes should override this method to dump their internal
+ // state. If this method is overridden the derived class's implementation
+ // should call ConsumerBase::dumpLocked.
+ //
+ // This method must be called with mMutex locked.
virtual void dumpLocked(String8& result, const char* prefix, char* buffer,
- size_t SIZE) const;
+ size_t size) const;
// acquireBufferLocked fetches the next buffer from the BufferQueue and
// updates the buffer slot for the buffer returned.
+ //
+ // Derived classes should override this method to perform any
+ // initialization that must take place the first time a buffer is assigned
+ // to a slot. If it is overridden the derived class's implementation must
+ // call ConsumerBase::acquireBufferLocked.
virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
// releaseBufferLocked relinquishes control over a buffer, returning that
// control to the BufferQueue.
+ //
+ // Derived classes should override this method to perform any cleanup that
+ // must take place when a buffer is released back to the BufferQueue. If
+ // it is overridden the derived class's implementation must call
+ // ConsumerBase::acquireBufferLocked.
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
EGLSyncKHR eglFence, const sp<Fence>& fence);
@@ -189,17 +197,12 @@ 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.
+ // member variables are accessed or when any of the *Locked methods are
+ // called.
+ //
+ // This mutex is intended to be locked by derived classes.
mutable Mutex mMutex;
};
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 66c390a..98741c5 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -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);
@@ -271,7 +248,7 @@ private:
// slot and destroy the EGLImage in that slot. Otherwise it has no effect.
//
// This method must be called with mMutex locked.
- void freeBufferLocked(int slotIndex);
+ virtual void freeBufferLocked(int slotIndex);
// computeCurrentTransformMatrix computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
@@ -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;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index af19ac0..17bbfd1 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -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());
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 6666081..c0b20df 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -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,44 @@ 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.
+ if (mEglSlots[slot].mEglImage == EGL_NO_IMAGE_KHR) {
+ 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 +221,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 +302,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 +362,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 +453,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 +481,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
return UNKNOWN_ERROR;
}
glFlush();
- mEGLSlots[mCurrentTexture].mFence = fence;
+ mEglSlots[mCurrentTexture].mEglFence = fence;
}
return OK;
@@ -607,10 +579,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 +624,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 +703,22 @@ 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;
+ ConsumerBase::freeBufferLocked(slotIndex);
}
-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 +750,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]) {