diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 039e7b074..ae9916018 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -40,7 +40,6 @@ public: }; enum { NUM_BUFFER_SLOTS = 32 }; enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called from queueBuffer() each time an @@ -120,91 +119,8 @@ public: // connected to the specified client API. virtual status_t disconnect(int api); - // 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: - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() - : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. This gets - // set to mNextCrop each time queueBuffer gets called for this buffer. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. This - // gets set to mNextTransform each time queueBuffer gets called for this - // slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. This - // gets set to mNextScalingMode each time queueBuffer gets called for - // this slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // buf is the slot index of this buffer - int mBuf; - - }; - - // The following public functions is the consumer facing interface - - // acquire consumes a buffer by transferring its ownership to a consumer. - // buffer contains the GraphicBuffer and its corresponding information. - // buffer.mGraphicsBuffer will be NULL when the buffer has been already - // acquired by the consumer. - - status_t acquire(BufferItem *buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue pending a fence sync. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence); - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed. - status_t consumerDisconnect(); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setBufferCountServer set the buffer count. If the client has requested - // a buffer count using setBufferCount, the server-buffer count will - // take effect once the client sets the count back to zero. - status_t setBufferCountServer(int bufferCount); - - // isSynchronousMode returns whether the SurfaceTexture is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp& listener); - - -private: // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage) // for the given slot. void freeBufferLocked(int index); @@ -229,18 +145,20 @@ private: status_t setBufferCountServerLocked(int bufferCount); + enum { INVALID_BUFFER_SLOT = -1 }; + struct BufferSlot { BufferSlot() - : mEglDisplay(EGL_NO_DISPLAY), + : mEglImage(EGL_NO_IMAGE_KHR), + mEglDisplay(EGL_NO_DISPLAY), mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), - mFence(EGL_NO_SYNC_KHR), - mAcquireCalled(false) { + mFence(EGL_NO_SYNC_KHR) { mCrop.makeInvalid(); } @@ -248,6 +166,9 @@ private: // if no buffer has been allocated. sp mGraphicBuffer; + // mEglImage is the EGLImage created from mGraphicBuffer. + EGLImageKHR mEglImage; + // mEglDisplay is the EGLDisplay used to create mEglImage. EGLDisplay mEglDisplay; @@ -257,7 +178,6 @@ private: // FREE indicates that the buffer is not currently being used and // will not be used in the future until it gets dequeued and // subsequently queued by the client. - // aka "owned by BufferQueue, ready to be dequeued" FREE = 0, // DEQUEUED indicates that the buffer has been dequeued by the @@ -270,7 +190,6 @@ private: // dequeued by the client. That means that the current buffer can // be in either the DEQUEUED or QUEUED state. In asynchronous mode, // however, the current buffer is always in the QUEUED state. - // aka "owned by producer, ready to be queued" DEQUEUED = 1, // QUEUED indicates that the buffer has been queued by the client, @@ -280,11 +199,7 @@ private: // the current buffer may be dequeued by the client under some // circumstances. See the note about the current buffer in the // documentation for DEQUEUED. - // aka "owned by BufferQueue, ready to be acquired" QUEUED = 2, - - // aka "owned by consumer, ready to be released" - ACQUIRED = 3 }; // mBufferState is the current state of this buffer slot. @@ -321,9 +236,6 @@ private: // 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; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; }; // mSlots is the array of buffer slots that must be mirrored on the client @@ -333,6 +245,7 @@ private: // for a slot when requestBuffer is called with that slot's index. BufferSlot mSlots[NUM_BUFFER_SLOTS]; + // mDefaultWidth holds the default width of allocated buffers. It is used // in requestBuffers() if a width and height of zero is specified. uint32_t mDefaultWidth; @@ -358,6 +271,14 @@ private: // mServerBufferCount buffer count requested by the server-side int mServerBufferCount; + // mCurrentTexture is the buffer slot index of the buffer that is currently + // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, + // indicating that no buffer slot is currently bound to the texture. Note, + // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean + // that no buffer is bound to the texture. A call to setBufferCount will + // reset mCurrentTexture to INVALID_BUFFER_SLOT. + int mCurrentTexture; + // mNextCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mNextCrop; @@ -406,7 +327,7 @@ private: // mName is a string used to identify the BufferQueue in log messages. // It is set by the setName method. - String8 mConsumerName; + String8 mName; // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueue objects. It must be locked whenever the @@ -416,8 +337,6 @@ private: // mFrameCounter is the free running counter, incremented for every buffer queued // with the surface Texture. uint64_t mFrameCounter; - - bool mBufferHasBeenQueued; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 5531e539b..dcab049ef 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -153,8 +153,8 @@ public: void setName(const String8& name); // 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; + void dump(String8& result) const; + void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; protected: @@ -217,56 +217,6 @@ private: // browser's tile cache exceeds. const GLenum mTexTarget; - // SurfaceTexture maintains EGL information about GraphicBuffers that corresponds - // directly with BufferQueue's buffers - struct EGLSlot { - EGLSlot() - : mEglImage(EGL_NO_IMAGE_KHR), - mEglDisplay(EGL_NO_DISPLAY), - mFence(EGL_NO_SYNC_KHR) { - } - - sp mGraphicBuffer; - - // mEglImage is the EGLImage created from mGraphicBuffer. - EGLImageKHR mEglImage; - - // mEglDisplay is the EGLDisplay used to create mEglImage. - EGLDisplay mEglDisplay; - - // mFence is the EGL sync object that must signal before the buffer - // 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; - }; - - EGLSlot mEGLSlots[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; - - // 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; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index f4214c7d4..0791de226 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -15,7 +15,6 @@ */ #define LOG_TAG "BufferQueue" -//#define LOG_NDEBUG 0 #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES @@ -28,7 +27,6 @@ #include #include -#include // This compile option causes SurfaceTexture to return the buffer that is currently // attached to the GL texture from dequeueBuffer when no other buffers are @@ -44,11 +42,11 @@ #endif // Macros for including the BufferQueue name in log messages -#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) namespace android { @@ -65,17 +63,17 @@ BufferQueue::BufferQueue( bool allowSynchronousMode ) : mBufferCount(MIN_ASYNC_BUFFER_SLOTS), mClientBufferCount(0), mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), + mCurrentTexture(INVALID_BUFFER_SLOT), mNextTransform(0), mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mSynchronousMode(false), mAllowSynchronousMode(allowSynchronousMode), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false) + mFrameCounter(0) { // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); + mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); ST_LOGV("BufferQueue"); sp composer(ComposerService::getComposerService()); @@ -121,23 +119,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { return OK; } -bool BufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -void BufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -void BufferQueue::setFrameAvailableListener( - const sp& listener) { - ST_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - status_t BufferQueue::setBufferCount(int bufferCount) { ST_LOGV("setBufferCount: count=%d", bufferCount); Mutex::Autolock lock(mMutex); @@ -179,7 +160,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) { freeAllBuffersLocked(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mDequeueCondition.signal(); return OK; @@ -295,7 +276,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } @@ -309,10 +290,19 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, dequeuedCount++; } + // if buffer is FREE it CANNOT be current + ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), + "dequeueBuffer: buffer %d is both FREE and current!", + i); + if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) { - // This functionality has been temporarily removed so - // BufferQueue and SurfaceTexture can be refactored into - // separate objects + if (state == BufferSlot::FREE || i == mCurrentTexture) { + foundSync = i; + if (i != mCurrentTexture) { + found = i; + break; + } + } } else { if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid @@ -341,7 +331,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // See whether a buffer has been queued since the last // setBufferCount so we know whether to perform the // MIN_UNDEQUEUED_BUFFERS check below. - if (mBufferHasBeenQueued) { + bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; + if (bufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); @@ -413,23 +404,27 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, if (updateFormat) { mPixelFormat = format; } - - mSlots[buf].mAcquireCalled = false; mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mFence = EGL_NO_SYNC_KHR; - mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - - - - + if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[buf].mEglDisplay, + mSlots[buf].mEglImage); + mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; + } + if (mCurrentTexture == buf) { + // The current texture no longer references the buffer in this slot + // since we just allocated a new buffer. + mCurrentTexture = INVALID_BUFFER_SLOT; + } returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; fence = mSlots[buf].mFence; mSlots[buf].mFence = EGL_NO_SYNC_KHR; - } // end lock scope + } if (fence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); @@ -442,7 +437,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ALOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(dpy, fence); - } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, @@ -502,6 +496,9 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp, ST_LOGE("queueBuffer: slot %d is not owned by the client " "(state=%d)", buf, mSlots[buf].mBufferState); return -EINVAL; + } else if (buf == mCurrentTexture) { + ST_LOGE("queueBuffer: slot %d is current!", buf); + return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " "buffer", buf); @@ -541,7 +538,6 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp, mFrameCounter++; mSlots[buf].mFrameNumber = mFrameCounter; - mBufferHasBeenQueued = true; mDequeueCondition.signal(); *outWidth = mDefaultWidth; @@ -651,9 +647,6 @@ status_t BufferQueue::connect(int api, err = -EINVAL; break; } - - mBufferHasBeenQueued = false; - return err; } @@ -694,185 +687,26 @@ status_t BufferQueue::disconnect(int api) { return err; } -void BufferQueue::dump(String8& result) const -{ - char buffer[1024]; - BufferQueue::dump(result, "", buffer, 1024); -} - -void BufferQueue::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x}\n" - ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, - mNextCrop.bottom, mNextTransform - ); - result.append(buffer); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - snprintf(buffer, SIZE, - "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, FIFO(%d)={%s}\n", - prefix, mBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mPixelFormat, fifoSize, fifo.string()); - result.append(buffer); - - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp - ); - result.append(buffer); - - const sp& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - void BufferQueue::freeBufferLocked(int i) { mSlots[i].mGraphicBuffer = 0; mSlots[i].mBufferState = BufferSlot::FREE; mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - - // destroy fence as BufferQueue now takes ownership - if (mSlots[i].mFence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence); - mSlots[i].mFence = EGL_NO_SYNC_KHR; + if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); + mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[i].mEglDisplay = EGL_NO_DISPLAY; } } void BufferQueue::freeAllBuffersLocked() { ALOGW_IF(!mQueue.isEmpty(), "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); } } -status_t BufferQueue::acquire(BufferItem *buffer) { - Mutex::Autolock _l(mMutex); - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - if (mSlots[buf].mAcquireCalled) { - buffer->mGraphicBuffer = NULL; - } - else { - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - } - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mBuf = buf; - mSlots[buf].mAcquireCalled = true; - - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mQueue.erase(front); - } - else { - return -EINVAL; //should be a better return code - } - - return OK; -} - -status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, - EGLSyncKHR fence) { - Mutex::Autolock _l(mMutex); - - if (buf == INVALID_BUFFER_SLOT) { - return -EINVAL; - } - - mSlots[buf].mEglDisplay = display; - mSlots[buf].mFence = fence; - - // The current buffer becomes FREE if it was still in the queued - // state. If it has already been given to the client - // (synchronous mode), then it stays in DEQUEUED state. - if (mSlots[buf].mBufferState == BufferSlot::QUEUED - || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mBufferState = BufferSlot::FREE; - } - mDequeueCondition.signal(); - - return OK; -} - -status_t BufferQueue::consumerDisconnect() { - Mutex::Autolock lock(mMutex); - // Once the SurfaceTexture disconnects, the BufferQueue - // is considered abandoned - mAbandoned = true; - freeAllBuffersLocked(); - mDequeueCondition.signal(); - return OK; -} - -status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return OK; -} - -status_t BufferQueue::setBufferCountServer(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setBufferCountServerLocked(bufferCount); -} - void BufferQueue::freeAllBuffersExceptHeadLocked() { ALOGW_IF(!mQueue.isEmpty(), "freeAllBuffersExceptCurrentLocked called but mQueue is not empty"); @@ -881,7 +715,7 @@ void BufferQueue::freeAllBuffersExceptHeadLocked() { Fifo::iterator front(mQueue.begin()); head = *front; } - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (i != head) { freeBufferLocked(i); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index ee5deb3b2..a7bfc613a 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -97,11 +97,6 @@ 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) : @@ -114,13 +109,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, #else mUseFenceSync(false), #endif - mTexTarget(texTarget), - mAbandoned(false), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) + mTexTarget(texTarget) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - BufferQueue::setConsumerName(mName); ST_LOGV("SurfaceTexture"); memcpy(mCurrentTransformMatrix, mtxIdentity, @@ -129,18 +119,28 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, SurfaceTexture::~SurfaceTexture() { ST_LOGV("~SurfaceTexture"); - abandon(); + freeAllBuffersLocked(); } status_t SurfaceTexture::setBufferCountServer(int bufferCount) { Mutex::Autolock lock(mMutex); - return BufferQueue::setBufferCountServer(bufferCount); + return setBufferCountServerLocked(bufferCount); } status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { - return BufferQueue::setDefaultBufferSize(w, h); + ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); + if (!w || !h) { + ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", + w, h); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + mDefaultWidth = w; + mDefaultHeight = h; + return OK; } status_t SurfaceTexture::updateTexImage() { @@ -152,35 +152,23 @@ status_t SurfaceTexture::updateTexImage() { return NO_INIT; } - BufferItem item; - // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - if (acquire(&item) == 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(mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mEglImage); - mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - mEGLSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - } - mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer; - } + if (!mQueue.empty()) { + Fifo::iterator front(mQueue.begin()); + int buf = *front; // Update the GL texture object. - EGLImageKHR image = mEGLSlots[buf].mEglImage; + EGLImageKHR image = mSlots[buf].mEglImage; EGLDisplay dpy = eglGetCurrentDisplay(); if (image == EGL_NO_IMAGE_KHR) { - if (item.mGraphicBuffer == 0) { + if (mSlots[buf].mGraphicBuffer == 0) { ST_LOGE("buffer at slot %d is null", buf); return BAD_VALUE; } - image = createImage(dpy, item.mGraphicBuffer); - mEGLSlots[buf].mEglImage = image; - mEGLSlots[buf].mEglDisplay = dpy; + image = createImage(dpy, mSlots[buf].mGraphicBuffer); + mSlots[buf].mEglImage = image; + mSlots[buf].mEglDisplay = dpy; if (image == EGL_NO_IMAGE_KHR) { // NOTE: if dpy was invalid, createImage() is guaranteed to // fail. so we'd end up here. @@ -203,8 +191,6 @@ status_t SurfaceTexture::updateTexImage() { failed = true; } if (failed) { - releaseBuffer(buf, mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mFence); return -EINVAL; } @@ -215,37 +201,40 @@ status_t SurfaceTexture::updateTexImage() { if (fence == EGL_NO_SYNC_KHR) { ALOGE("updateTexImage: error creating fence: %#x", eglGetError()); - releaseBuffer(buf, mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mFence); return -EINVAL; } glFlush(); - mEGLSlots[mCurrentTexture].mFence = fence; + mSlots[mCurrentTexture].mFence = fence; } } ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, item.mGraphicBuffer->handle); + buf, mSlots[buf].mGraphicBuffer->handle); - // release old buffer - releaseBuffer(mCurrentTexture, - mEGLSlots[mCurrentTexture].mEglDisplay, - mEGLSlots[mCurrentTexture].mFence); + if (mCurrentTexture != INVALID_BUFFER_SLOT) { + // The current buffer becomes FREE if it was still in the queued + // state. If it has already been given to the client + // (synchronous mode), then it stays in DEQUEUED state. + if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) { + mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE; + } + } // Update the SurfaceTexture state. mCurrentTexture = buf; - mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; + mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; + mCurrentCrop = mSlots[buf].mCrop; + mCurrentTransform = mSlots[buf].mTransform; + mCurrentScalingMode = mSlots[buf].mScalingMode; + mCurrentTimestamp = mSlots[buf].mTimestamp; computeCurrentTransformMatrix(); // Now that we've passed the point at which failures can happen, // it's safe to remove the buffer from the front of the queue. - + mQueue.erase(front); + mDequeueCondition.signal(); } else { // We always bind the texture even if we don't update its contents. glBindTexture(mTexTarget, mTexName); @@ -311,7 +300,7 @@ void SurfaceTexture::computeCurrentTransformMatrix() { } } - sp& buf(mCurrentTextureBuf); + sp& buf(mSlots[mCurrentTexture].mGraphicBuffer); float tx, ty, sx, sy; if (!mCurrentCrop.isEmpty()) { // In order to prevent bilinear sampling at the of the crop rectangle we @@ -383,7 +372,7 @@ void SurfaceTexture::setFrameAvailableListener( const sp& listener) { ST_LOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); - BufferQueue::setFrameAvailableListener(listener); + mFrameAvailableListener = listener; } EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, @@ -424,33 +413,22 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const { bool SurfaceTexture::isSynchronousMode() const { Mutex::Autolock lock(mMutex); - return BufferQueue::isSynchronousMode(); + return mSynchronousMode; } + + void SurfaceTexture::abandon() { Mutex::Autolock lock(mMutex); + mQueue.clear(); mAbandoned = true; mCurrentTextureBuf.clear(); - - // destroy all egl buffers - for (int i =0; i < NUM_BUFFER_SLOTS; i++) { - mEGLSlots[i].mGraphicBuffer = 0; - if (mEGLSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mEGLSlots[i].mEglDisplay, - mEGLSlots[i].mEglImage); - mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR; - mEGLSlots[i].mEglDisplay = EGL_NO_DISPLAY; - } - } - - // disconnect from the BufferQueue - BufferQueue::consumerDisconnect(); + freeAllBuffersLocked(); + mDequeueCondition.signal(); } void SurfaceTexture::setName(const String8& name) { - Mutex::Autolock _l(mMutex); mName = name; - BufferQueue::setConsumerName(name); } void SurfaceTexture::dump(String8& result) const @@ -463,19 +441,68 @@ void SurfaceTexture::dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const { Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, "%smTexName=%d\n", prefix, mTexName); + snprintf(buffer, SIZE, + "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " + "mPixelFormat=%d, mTexName=%d\n", + prefix, mBufferCount, mSynchronousMode, mDefaultWidth, + mDefaultHeight, mPixelFormat, mTexName); result.append(buffer); + String8 fifo; + int fifoSize = 0; + Fifo::const_iterator i(mQueue.begin()); + while (i != mQueue.end()) { + snprintf(buffer, SIZE, "%02d ", *i++); + fifoSize++; + fifo.append(buffer); + } + snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" - ,prefix, mCurrentCrop.left, + "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" + "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n" + , + prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture + mCurrentTransform, mCurrentTexture, + prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, + mNextCrop.bottom, mNextTransform, fifoSize, fifo.string() ); result.append(buffer); + struct { + const char * operator()(int state) const { + switch (state) { + case BufferSlot::DEQUEUED: return "DEQUEUED"; + case BufferSlot::QUEUED: return "QUEUED"; + case BufferSlot::FREE: return "FREE"; + default: return "Unknown"; + } + } + } stateName; - BufferQueue::dump(result, prefix, buffer, SIZE); + for (int i=0 ; i":" ", i, + stateName(slot.mBufferState), + slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, + slot.mCrop.bottom, slot.mTransform, slot.mTimestamp + ); + result.append(buffer); + + const sp& buf(slot.mGraphicBuffer); + if (buf != NULL) { + snprintf(buffer, SIZE, + ", %p [%4ux%4u:%4u,%3X]", + buf->handle, buf->width, buf->height, buf->stride, + buf->format); + result.append(buffer); + } + result.append("\n"); + } } static void mtxMul(float out[16], const float a[16], const float b[16]) {