diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index d6ae5e9de..9d589cf99 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -285,6 +285,8 @@ public: uint32_t getTransform(int buffer) const; status_t resize(int newNumBuffers); + status_t grow(int newNumBuffers); + status_t shrink(int newNumBuffers); SharedBufferStack::Statistics getStats() const; @@ -346,6 +348,14 @@ private: int mNumBuffers; BufferList mBufferList; + struct BuffersAvailableCondition : public ConditionBase { + int mNumBuffers; + inline BuffersAvailableCondition(SharedBufferServer* sbs, + int numBuffers); + inline bool operator()() const; + inline const char* name() const { return "BuffersAvailableCondition"; } + }; + struct UnlockUpdate : public UpdateBase { const int lockedBuffer; inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 8f583f060..3b2ef848b 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -265,6 +265,14 @@ bool SharedBufferClient::LockCondition::operator()() const { (stack.queued > 0 && stack.inUse != buf)); } +SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition( + SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs), + mNumBuffers(numBuffers) { +} +bool SharedBufferServer::BuffersAvailableCondition::operator()() const { + return stack.available == mNumBuffers; +} + // ---------------------------------------------------------------------------- SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb) @@ -448,6 +456,7 @@ status_t SharedBufferClient::queue(int buf) const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); + return err; } @@ -492,6 +501,7 @@ status_t SharedBufferClient::setBufferCount( if (err == NO_ERROR) { mNumBuffers = bufferCount; queued_head = (stack.head + stack.queued) % mNumBuffers; + tail = computeTail(); } return err; } @@ -606,17 +616,24 @@ uint32_t SharedBufferServer::getTransform(int buf) const */ status_t SharedBufferServer::resize(int newNumBuffers) { - if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX) + if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN || + (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) { return BAD_VALUE; + } RWLock::AutoWLock _l(mLock); - // for now we're not supporting shrinking - const int numBuffers = mNumBuffers; - if (newNumBuffers < numBuffers) - return BAD_VALUE; + if (newNumBuffers < mNumBuffers) { + return shrink(newNumBuffers); + } else { + return grow(newNumBuffers); + } +} +status_t SharedBufferServer::grow(int newNumBuffers) +{ SharedBufferStack& stack( *mSharedStack ); + const int numBuffers = mNumBuffers; const int extra = newNumBuffers - numBuffers; // read the head, make sure it's valid @@ -650,6 +667,54 @@ status_t SharedBufferServer::resize(int newNumBuffers) return NO_ERROR; } +status_t SharedBufferServer::shrink(int newNumBuffers) +{ + SharedBufferStack& stack( *mSharedStack ); + + // Shrinking is only supported if there are no buffers currently dequeued. + int32_t avail = stack.available; + int32_t queued = stack.queued; + if (avail + queued != mNumBuffers) { + return INVALID_OPERATION; + } + + // Wait for any queued buffers to be displayed. + BuffersAvailableCondition condition(this, mNumBuffers); + status_t err = waitForCondition(condition); + if (err < 0) { + return err; + } + + // Reset head to index 0 and make it refer to buffer 0. The same renaming + // (head -> 0) is done in the BufferManager. + int32_t head = stack.head; + int8_t* index = const_cast(stack.index); + for (int8_t i = 0; i < newNumBuffers; i++) { + index[i] = i; + } + stack.head = 0; + stack.headBuf = 0; + + // If one of the buffers is in use it must be the head buffer, which we are + // renaming to buffer 0. + if (stack.inUse > 0) { + stack.inUse = 0; + } + + // Free the buffers from the end of the list that are no longer needed. + for (int i = newNumBuffers; i < mNumBuffers; i++) { + mBufferList.remove(i); + } + + // Tell the client to reallocate all the buffers. + reallocateAll(); + + mNumBuffers = newNumBuffers; + stack.available = newNumBuffers; + + return NO_ERROR; +} + SharedBufferStack::Statistics SharedBufferServer::getStats() const { SharedBufferStack& stack( *mSharedStack ); diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index c1e00ca68..9467a4cf0 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -855,6 +855,12 @@ int Surface::setBufferCount(int bufferCount) status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc); LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", bufferCount, strerror(-err)); + + if (err == NO_ERROR) { + // Clear out any references to the old buffers. + mBuffers.clear(); + } + return err; } diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp index f409f4828..7ef59269b 100644 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp @@ -32,7 +32,8 @@ void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); int main(int argc, char** argv) { SharedClient client; - SharedBufferServer s(&client, 0, 4, 0); + sp ps(new SharedBufferServer(&client, 0, 4, 0)); + SharedBufferServer& s(*ps); SharedBufferClient c(&client, 0, 4, 0); printf("basic test 0\n"); @@ -67,6 +68,10 @@ int main(int argc, char** argv) int list3[6] = {3, 2, 1, 4, 5, 0}; test0(s, c, 6, list3); + c.setBufferCount(4, resize); + int list4[4] = {1, 2, 3, 0}; + test0(s, c, 4, list4); + return 0; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1b06843df..7be58c654 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -340,8 +340,10 @@ status_t Layer::setBufferCount(int bufferCount) // NOTE: lcblk->resize() is protected by an internal lock status_t err = lcblk->resize(bufferCount); - if (err == NO_ERROR) - mBufferManager.resize(bufferCount); + if (err == NO_ERROR) { + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + mBufferManager.resize(bufferCount, mFlinger, dpy); + } return err; } @@ -774,9 +776,52 @@ Layer::BufferManager::~BufferManager() { } -status_t Layer::BufferManager::resize(size_t size) +status_t Layer::BufferManager::resize(size_t size, + const sp& flinger, EGLDisplay dpy) { Mutex::Autolock _l(mLock); + + if (size < mNumBuffers) { + // Move the active texture into slot 0 + BufferData activeBufferData = mBufferData[mActiveBuffer]; + mBufferData[mActiveBuffer] = mBufferData[0]; + mBufferData[0] = activeBufferData; + mActiveBuffer = 0; + + // Free the buffers that are no longer needed. + for (size_t i = size; i < mNumBuffers; i++) { + mBufferData[i].buffer = 0; + + // Create a message to destroy the textures on SurfaceFlinger's GL + // thread. + class MessageDestroyTexture : public MessageBase { + Image mTexture; + EGLDisplay mDpy; + public: + MessageDestroyTexture(const Image& texture, EGLDisplay dpy) + : mTexture(texture), mDpy(dpy) { } + virtual bool handler() { + status_t err = Layer::BufferManager::destroyTexture( + &mTexture, mDpy); + LOGE_IF(err<0, "error destroying texture: %d (%s)", + mTexture.name, strerror(-err)); + return true; // XXX: err == 0; ???? + } + }; + + MessageDestroyTexture *msg = new MessageDestroyTexture( + mBufferData[i].texture, dpy); + + // Don't allow this texture to be cleaned up by + // BufferManager::destroy. + mBufferData[i].texture.name = -1U; + mBufferData[i].texture.image = EGL_NO_IMAGE_KHR; + + // Post the message to the SurfaceFlinger object. + flinger->postMessageAsync(msg); + } + } + mNumBuffers = size; return NO_ERROR; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index caa6d1711..07434cf86 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -177,7 +177,8 @@ private: sp detachBuffer(size_t index); status_t attachBuffer(size_t index, const sp& buffer); // resize the number of active buffers - status_t resize(size_t size); + status_t resize(size_t size, const sp& flinger, + EGLDisplay dpy); // ---------------------------------------------- // must be called from GL thread