Loading include/gui/ISurfaceTexture.h +11 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,10 @@ public: protected: friend class SurfaceTextureClient; enum { BUFFER_NEEDS_REALLOCATION = 1 }; enum { BUFFER_NEEDS_REALLOCATION = 0x1, RELEASE_ALL_BUFFERS = 0x2, }; // requestBuffer requests a new buffer for the given index. The server (i.e. // the ISurfaceTexture implementation) assigns the newly created buffer to Loading Loading @@ -94,6 +97,13 @@ protected: // query retrieves some information for this surface // 'what' tokens allowed are that of android_natives.h virtual int query(int what, int* value) = 0; // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. virtual status_t setSynchronousMode(bool enabled) = 0; }; // ---------------------------------------------------------------------------- Loading include/gui/SurfaceTexture.h +28 −10 Original line number Diff line number Diff line Loading @@ -38,7 +38,10 @@ class IGraphicBufferAlloc; class SurfaceTexture : public BnSurfaceTexture { public: enum { MIN_UNDEQUEUED_BUFFERS = 2 }; enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1 }; enum { MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1, MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS }; enum { NUM_BUFFER_SLOTS = 32 }; struct FrameAvailableListener : public virtual RefBase { Loading Loading @@ -78,6 +81,13 @@ public: virtual int query(int what, int* value); // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. virtual status_t setSynchronousMode(bool enabled); // updateTexImage sets the image contents of the target texture to that of // the most recently queued buffer. // Loading @@ -85,6 +95,11 @@ public: // target texture belongs is bound to the calling thread. status_t updateTexImage(); // 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); // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix // associated with the texture image set by the most recent call to // updateTexImage. Loading Loading @@ -142,13 +157,6 @@ public: // getCurrentTransform returns the transform of the current buffer uint32_t getCurrentTransform() const; // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. status_t setSynchronousMode(bool enabled); protected: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for Loading @@ -163,6 +171,8 @@ private: EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer); status_t setBufferCountServerLocked(int bufferCount); enum { INVALID_BUFFER_SLOT = -1 }; struct BufferSlot { Loading Loading @@ -234,10 +244,18 @@ private: uint32_t mPixelFormat; // mBufferCount is the number of buffer slots that the client and server // must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by // calling setBufferCount. // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed // by calling setBufferCount or setBufferCountServer int mBufferCount; // mRequestedBufferCount is the number of buffer slots requested by the // client. The default is zero, which means the client doesn't care how // many buffers there is. int mClientBufferCount; // 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, Loading include/gui/SurfaceTextureClient.h +0 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,6 @@ private: int getConnectedApi() const; enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS }; enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS }; enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; Loading libs/gui/ISurfaceTexture.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ enum { SET_TRANSFORM, GET_ALLOCATOR, QUERY, SET_SYNCHRONOUS_MODE, }; Loading Loading @@ -144,6 +145,16 @@ public: return result; } virtual status_t setSynchronousMode(bool enabled) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(enabled); remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply); status_t result = reply.readInt32(); return result; } }; IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture"); Loading Loading @@ -230,6 +241,13 @@ status_t BnSurfaceTexture::onTransact( reply->writeInt32(res); return NO_ERROR; } break; case SET_SYNCHRONOUS_MODE: { CHECK_INTERFACE(ISurfaceTexture, data, reply); bool enabled = data.readInt32(); status_t res = setSynchronousMode(enabled); reply->writeInt32(res); return NO_ERROR; } break; } return BBinder::onTransact(code, data, reply, flags); } Loading libs/gui/SurfaceTexture.cpp +153 −21 Original line number Diff line number Diff line Loading @@ -81,7 +81,9 @@ SurfaceTexture::SurfaceTexture(GLuint tex) : mDefaultWidth(1), mDefaultHeight(1), mPixelFormat(PIXEL_FORMAT_RGBA_8888), mBufferCount(MIN_BUFFER_SLOTS), mBufferCount(MIN_ASYNC_BUFFER_SLOTS), mClientBufferCount(0), mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES), mCurrentTransform(0), Loading @@ -100,22 +102,79 @@ SurfaceTexture::~SurfaceTexture() { freeAllBuffers(); } status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { if (bufferCount > NUM_BUFFER_SLOTS) return BAD_VALUE; // special-case, nothing to do if (bufferCount == mBufferCount) return OK; if (!mClientBufferCount && bufferCount >= mBufferCount) { // easy, we just have more buffers mBufferCount = bufferCount; mServerBufferCount = bufferCount; mDequeueCondition.signal(); } else { // we're here because we're either // - reducing the number of available buffers // - or there is a client-buffer-count in effect // less than 2 buffers is never allowed if (bufferCount < 2) return BAD_VALUE; // when there is non client-buffer-count in effect, the client is not // allowed to dequeue more than one buffer at a time, // so the next time they dequeue a buffer, we know that they don't // own one. the actual resizing will happen during the next // dequeueBuffer. mServerBufferCount = bufferCount; } return OK; } status_t SurfaceTexture::setBufferCountServer(int bufferCount) { Mutex::Autolock lock(mMutex); return setBufferCountServerLocked(bufferCount); } status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); Mutex::Autolock lock(mMutex); // Error out if the user has dequeued buffers for (int i=0 ; i<mBufferCount ; i++) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { LOGE("setBufferCount: client owns some buffers"); return -EINVAL; } } if (bufferCount == 0) { const int minBufferSlots = mSynchronousMode ? MIN_BUFFER_SLOTS-1 : MIN_BUFFER_SLOTS; MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; mClientBufferCount = 0; bufferCount = (mServerBufferCount >= minBufferSlots) ? mServerBufferCount : minBufferSlots; return setBufferCountServerLocked(bufferCount); } if (bufferCount < minBufferSlots) { // We don't allow the client to set a buffer-count less than // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it. if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) { return BAD_VALUE; } // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. freeAllBuffers(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mQueue.reserve(mSynchronousMode ? mBufferCount : 1); mDequeueCondition.signal(); return OK; } Loading Loading @@ -152,10 +211,56 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, } Mutex::Autolock lock(mMutex); status_t returnFlags(OK); int found, foundSync; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { // We need to wait for the FIFO to drain if the number of buffer // needs to change. // // The condition "number of buffer needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() // - OR - // setBufferCountServer() was set to a value incompatible with // the synchronization mode (for instance because the sync mode // changed since) // // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. int minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // wait for the FIFO to drain while (!mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; } if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // here we're guaranteed that mQueue is empty freeAllBuffers(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; mCurrentTexture = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; Loading @@ -172,23 +277,35 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, } } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mClientBufferCount && dequeuedCount) { return -EINVAL; } // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)", MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), dequeuedCount); return -EBUSY; } // we're in synchronous mode and didn't find a buffer, we need to wait // for for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { mDequeueCondition.wait(mMutex); } } if (mSynchronousMode) { // we're dequeuing more buffers than allowed in synchronous mode if ((mBufferCount - (dequeuedCount+1)) < MIN_UNDEQUEUED_BUFFERS-1) return -EBUSY; if (found == INVALID_BUFFER_SLOT) { if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { // foundSync guaranteed to be != INVALID_BUFFER_SLOT found = foundSync; } } if (found == INVALID_BUFFER_SLOT) { return -EBUSY; Loading Loading @@ -238,22 +355,31 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; } return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } return OK; return returnFlags; } status_t SurfaceTexture::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); status_t err = OK; if (!enabled) { // going to asynchronous mode, drain the queue while (mSynchronousMode != enabled && !mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } } if (mSynchronousMode != enabled) { // - if we're going to asynchronous mode, the queue is guaranteed to be // empty here // - if the client set the number of buffers, we're guaranteed that // we have at least 3 (because we don't allow less) mSynchronousMode = enabled; freeAllBuffers(); mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mQueue.reserve(mSynchronousMode ? mBufferCount : 1); mDequeueCondition.signal(); } return NO_ERROR; return err; } status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { Loading @@ -267,6 +393,9 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { LOGE("queueBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); return -EINVAL; } else if (buf == mCurrentTexture) { LOGE("queueBuffer: slot %d is current!", buf); return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", buf); Loading Loading @@ -342,6 +471,9 @@ status_t SurfaceTexture::updateTexImage() { Fifo::iterator front(mQueue.begin()); buf = *front; mQueue.erase(front); if (mQueue.isEmpty()) { mDequeueCondition.signal(); } } // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT, Loading Loading
include/gui/ISurfaceTexture.h +11 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,10 @@ public: protected: friend class SurfaceTextureClient; enum { BUFFER_NEEDS_REALLOCATION = 1 }; enum { BUFFER_NEEDS_REALLOCATION = 0x1, RELEASE_ALL_BUFFERS = 0x2, }; // requestBuffer requests a new buffer for the given index. The server (i.e. // the ISurfaceTexture implementation) assigns the newly created buffer to Loading Loading @@ -94,6 +97,13 @@ protected: // query retrieves some information for this surface // 'what' tokens allowed are that of android_natives.h virtual int query(int what, int* value) = 0; // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. virtual status_t setSynchronousMode(bool enabled) = 0; }; // ---------------------------------------------------------------------------- Loading
include/gui/SurfaceTexture.h +28 −10 Original line number Diff line number Diff line Loading @@ -38,7 +38,10 @@ class IGraphicBufferAlloc; class SurfaceTexture : public BnSurfaceTexture { public: enum { MIN_UNDEQUEUED_BUFFERS = 2 }; enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1 }; enum { MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1, MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS }; enum { NUM_BUFFER_SLOTS = 32 }; struct FrameAvailableListener : public virtual RefBase { Loading Loading @@ -78,6 +81,13 @@ public: virtual int query(int what, int* value); // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. virtual status_t setSynchronousMode(bool enabled); // updateTexImage sets the image contents of the target texture to that of // the most recently queued buffer. // Loading @@ -85,6 +95,11 @@ public: // target texture belongs is bound to the calling thread. status_t updateTexImage(); // 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); // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix // associated with the texture image set by the most recent call to // updateTexImage. Loading Loading @@ -142,13 +157,6 @@ public: // getCurrentTransform returns the transform of the current buffer uint32_t getCurrentTransform() const; // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until // a buffer is available, the currently bound buffer can be dequeued and // queued buffers will be retired in order. // The default mode is asynchronous. status_t setSynchronousMode(bool enabled); protected: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for Loading @@ -163,6 +171,8 @@ private: EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer); status_t setBufferCountServerLocked(int bufferCount); enum { INVALID_BUFFER_SLOT = -1 }; struct BufferSlot { Loading Loading @@ -234,10 +244,18 @@ private: uint32_t mPixelFormat; // mBufferCount is the number of buffer slots that the client and server // must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by // calling setBufferCount. // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed // by calling setBufferCount or setBufferCountServer int mBufferCount; // mRequestedBufferCount is the number of buffer slots requested by the // client. The default is zero, which means the client doesn't care how // many buffers there is. int mClientBufferCount; // 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, Loading
include/gui/SurfaceTextureClient.h +0 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,6 @@ private: int getConnectedApi() const; enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS }; enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS }; enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; Loading
libs/gui/ISurfaceTexture.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ enum { SET_TRANSFORM, GET_ALLOCATOR, QUERY, SET_SYNCHRONOUS_MODE, }; Loading Loading @@ -144,6 +145,16 @@ public: return result; } virtual status_t setSynchronousMode(bool enabled) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(enabled); remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply); status_t result = reply.readInt32(); return result; } }; IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture"); Loading Loading @@ -230,6 +241,13 @@ status_t BnSurfaceTexture::onTransact( reply->writeInt32(res); return NO_ERROR; } break; case SET_SYNCHRONOUS_MODE: { CHECK_INTERFACE(ISurfaceTexture, data, reply); bool enabled = data.readInt32(); status_t res = setSynchronousMode(enabled); reply->writeInt32(res); return NO_ERROR; } break; } return BBinder::onTransact(code, data, reply, flags); } Loading
libs/gui/SurfaceTexture.cpp +153 −21 Original line number Diff line number Diff line Loading @@ -81,7 +81,9 @@ SurfaceTexture::SurfaceTexture(GLuint tex) : mDefaultWidth(1), mDefaultHeight(1), mPixelFormat(PIXEL_FORMAT_RGBA_8888), mBufferCount(MIN_BUFFER_SLOTS), mBufferCount(MIN_ASYNC_BUFFER_SLOTS), mClientBufferCount(0), mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES), mCurrentTransform(0), Loading @@ -100,22 +102,79 @@ SurfaceTexture::~SurfaceTexture() { freeAllBuffers(); } status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { if (bufferCount > NUM_BUFFER_SLOTS) return BAD_VALUE; // special-case, nothing to do if (bufferCount == mBufferCount) return OK; if (!mClientBufferCount && bufferCount >= mBufferCount) { // easy, we just have more buffers mBufferCount = bufferCount; mServerBufferCount = bufferCount; mDequeueCondition.signal(); } else { // we're here because we're either // - reducing the number of available buffers // - or there is a client-buffer-count in effect // less than 2 buffers is never allowed if (bufferCount < 2) return BAD_VALUE; // when there is non client-buffer-count in effect, the client is not // allowed to dequeue more than one buffer at a time, // so the next time they dequeue a buffer, we know that they don't // own one. the actual resizing will happen during the next // dequeueBuffer. mServerBufferCount = bufferCount; } return OK; } status_t SurfaceTexture::setBufferCountServer(int bufferCount) { Mutex::Autolock lock(mMutex); return setBufferCountServerLocked(bufferCount); } status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); Mutex::Autolock lock(mMutex); // Error out if the user has dequeued buffers for (int i=0 ; i<mBufferCount ; i++) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { LOGE("setBufferCount: client owns some buffers"); return -EINVAL; } } if (bufferCount == 0) { const int minBufferSlots = mSynchronousMode ? MIN_BUFFER_SLOTS-1 : MIN_BUFFER_SLOTS; MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; mClientBufferCount = 0; bufferCount = (mServerBufferCount >= minBufferSlots) ? mServerBufferCount : minBufferSlots; return setBufferCountServerLocked(bufferCount); } if (bufferCount < minBufferSlots) { // We don't allow the client to set a buffer-count less than // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it. if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) { return BAD_VALUE; } // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. freeAllBuffers(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mQueue.reserve(mSynchronousMode ? mBufferCount : 1); mDequeueCondition.signal(); return OK; } Loading Loading @@ -152,10 +211,56 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, } Mutex::Autolock lock(mMutex); status_t returnFlags(OK); int found, foundSync; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { // We need to wait for the FIFO to drain if the number of buffer // needs to change. // // The condition "number of buffer needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() // - OR - // setBufferCountServer() was set to a value incompatible with // the synchronization mode (for instance because the sync mode // changed since) // // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. int minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // wait for the FIFO to drain while (!mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; } if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // here we're guaranteed that mQueue is empty freeAllBuffers(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; mCurrentTexture = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; Loading @@ -172,23 +277,35 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, } } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mClientBufferCount && dequeuedCount) { return -EINVAL; } // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)", MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), dequeuedCount); return -EBUSY; } // we're in synchronous mode and didn't find a buffer, we need to wait // for for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { mDequeueCondition.wait(mMutex); } } if (mSynchronousMode) { // we're dequeuing more buffers than allowed in synchronous mode if ((mBufferCount - (dequeuedCount+1)) < MIN_UNDEQUEUED_BUFFERS-1) return -EBUSY; if (found == INVALID_BUFFER_SLOT) { if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { // foundSync guaranteed to be != INVALID_BUFFER_SLOT found = foundSync; } } if (found == INVALID_BUFFER_SLOT) { return -EBUSY; Loading Loading @@ -238,22 +355,31 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; } return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } return OK; return returnFlags; } status_t SurfaceTexture::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); status_t err = OK; if (!enabled) { // going to asynchronous mode, drain the queue while (mSynchronousMode != enabled && !mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } } if (mSynchronousMode != enabled) { // - if we're going to asynchronous mode, the queue is guaranteed to be // empty here // - if the client set the number of buffers, we're guaranteed that // we have at least 3 (because we don't allow less) mSynchronousMode = enabled; freeAllBuffers(); mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mQueue.reserve(mSynchronousMode ? mBufferCount : 1); mDequeueCondition.signal(); } return NO_ERROR; return err; } status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { Loading @@ -267,6 +393,9 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { LOGE("queueBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); return -EINVAL; } else if (buf == mCurrentTexture) { LOGE("queueBuffer: slot %d is current!", buf); return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", buf); Loading Loading @@ -342,6 +471,9 @@ status_t SurfaceTexture::updateTexImage() { Fifo::iterator front(mQueue.begin()); buf = *front; mQueue.erase(front); if (mQueue.isEmpty()) { mDequeueCondition.signal(); } } // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT, Loading