diff options
author | Mathias Agopian <mathias@google.com> | 2010-05-07 15:58:44 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2010-05-12 17:28:20 -0700 |
commit | b5b7f260da2c1a2a82e0311e2015d49a82f43667 (patch) | |
tree | 69976a2b04a39bfce83035777ea8d35e4a5fc401 | |
parent | d606de6bb6877dc4ab93ec0be0c6bda4a8ee1ce8 (diff) | |
download | frameworks_native-b5b7f260da2c1a2a82e0311e2015d49a82f43667.zip frameworks_native-b5b7f260da2c1a2a82e0311e2015d49a82f43667.tar.gz frameworks_native-b5b7f260da2c1a2a82e0311e2015d49a82f43667.tar.bz2 |
SharedBufferStack now can grow up to 16 buffers.
there is a new resize() api, which currently only allows growing.
Change-Id: Ia37b81b73be466d2491ffed7f3a23cd8e113c6fe
-rw-r--r-- | include/private/surfaceflinger/SharedBufferStack.h | 55 | ||||
-rw-r--r-- | include/surfaceflinger/ISurface.h | 2 | ||||
-rw-r--r-- | include/surfaceflinger/Surface.h | 1 | ||||
-rw-r--r-- | libs/surfaceflinger/Layer.cpp | 34 | ||||
-rw-r--r-- | libs/surfaceflinger/Layer.h | 2 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.cpp | 5 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.h | 2 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurface.cpp | 17 | ||||
-rw-r--r-- | libs/surfaceflinger_client/SharedBufferStack.cpp | 91 | ||||
-rw-r--r-- | libs/surfaceflinger_client/Surface.cpp | 21 |
10 files changed, 221 insertions, 9 deletions
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index 2504d39..c23832d 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -129,7 +129,7 @@ public: // ---------------------------------------------------------------------------- -// 4 KB max +// 32 KB max class SharedClient { public: @@ -166,7 +166,7 @@ public: protected: SharedClient* const mSharedClient; SharedBufferStack* const mSharedStack; - const int mNumBuffers; + int mNumBuffers; const int mIdentity; int32_t computeTail() const; @@ -217,6 +217,7 @@ public: bool needNewBuffer(int buffer) const; status_t setDirtyRegion(int buffer, const Region& reg); status_t setCrop(int buffer, const Rect& reg); + status_t setBufferCount(int bufferCount); private: friend struct Condition; @@ -269,13 +270,61 @@ public: status_t reallocate(); status_t assertReallocate(int buffer); int32_t getQueuedCount() const; - Region getDirtyRegion(int buffer) const; + status_t resize(int newNumBuffers); + SharedBufferStack::Statistics getStats() const; private: + /* + * BufferList is basically a fixed-capacity sorted-vector of + * unsigned 5-bits ints using a 32-bits int as storage. + * it has efficient iterators to find items in the list and not in the list. + */ + class BufferList { + size_t mCapacity; + uint32_t mList; + public: + BufferList(size_t c = NUM_BUFFER_MAX) : mCapacity(c), mList(0) { } + status_t add(int value); + status_t remove(int value); + + class const_iterator { + friend class BufferList; + uint32_t mask, curr; + const_iterator(uint32_t mask) : + mask(mask), curr(31 - __builtin_clz(mask)) { } + public: + inline bool operator == (const const_iterator& rhs) const { + return mask == rhs.mask; + } + inline bool operator != (const const_iterator& rhs) const { + return mask != rhs.mask; + } + inline int operator *() const { return curr; } + inline const const_iterator& operator ++(int) { + mask &= ~curr; + curr = 31 - __builtin_clz(mask); + return *this; + } + }; + + inline const_iterator begin() const { + return const_iterator(mList); + } + inline const_iterator end() const { + return const_iterator(0); + } + inline const_iterator free_begin() const { + uint32_t mask = (1 << (32-mCapacity)) - 1; + return const_iterator( ~(mList | mask) ); + } + }; + + BufferList mBufferList; + struct UnlockUpdate : public UpdateBase { const int lockedBuffer; inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h index 472f759..9476686 100644 --- a/include/surfaceflinger/ISurface.h +++ b/include/surfaceflinger/ISurface.h @@ -47,12 +47,14 @@ protected: POST_BUFFER, // one-way transaction CREATE_OVERLAY, REQUEST_BUFFER, + SET_BUFFER_COUNT, }; public: DECLARE_META_INTERFACE(Surface); virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0; + virtual status_t setBufferCount(int bufferCount) = 0; class BufferHeap { public: diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 7ab3a00..973780f 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -217,6 +217,7 @@ private: int connect(int api); int disconnect(int api); int crop(Rect const* rect); + int setBufferCount(int bufferCount); /* * private stuff... diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 71573ac..1fe997d 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -208,6 +208,30 @@ void Layer::onDraw(const Region& clip) const drawWithOpenGL(clip, tex); } + +status_t Layer::setBufferCount(int bufferCount) +{ + // this ensures our client doesn't go away while we're accessing + // the shared area. + sp<Client> ourClient(client.promote()); + if (ourClient == 0) { + // oops, the client is already gone + return DEAD_OBJECT; + } + + status_t err; + + // FIXME: resize() below is NOT thread-safe, we need to synchronize + // the users of lcblk in our process (ie: retire), and we assume the + // client is not mucking with the SharedStack, which is only enforced + // by construction, therefore we need to protect ourselves against + // buggy and malicious client (as always) + + err = lcblk->resize(bufferCount); + + return err; +} + sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) { sp<GraphicBuffer> buffer; @@ -642,6 +666,16 @@ sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) return buffer; } +status_t Layer::SurfaceLayer::setBufferCount(int bufferCount) +{ + status_t err = DEAD_OBJECT; + sp<Layer> owner(getOwner()); + if (owner != 0) { + err = owner->setBufferCount(bufferCount); + } + return err; +} + // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 26fb6c6..80fbd6a 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -89,6 +89,7 @@ private: uint32_t getEffectiveUsage(uint32_t usage) const; sp<GraphicBuffer> requestBuffer(int index, int usage); + status_t setBufferCount(int bufferCount); void destroy(); class SurfaceLayer : public LayerBaseClient::Surface { @@ -98,6 +99,7 @@ private: ~SurfaceLayer(); private: virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual status_t setBufferCount(int bufferCount); sp<Layer> getOwner() const { return static_cast<Layer*>(Surface::getOwner().get()); } diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index 7d8d43f..63b9520 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -621,6 +621,11 @@ sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) return NULL; } +status_t LayerBaseClient::Surface::setBufferCount(int bufferCount) +{ + return INVALID_OPERATION; +} + status_t LayerBaseClient::Surface::registerBuffers( const ISurface::BufferHeap& buffers) { diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index c500dcf..53b848f 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -302,6 +302,8 @@ public: private: virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual status_t setBufferCount(int bufferCount); + virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index bb86199..c5d0c0e 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -83,6 +83,16 @@ public: return buffer; } + virtual status_t setBufferCount(int bufferCount) + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + remote()->transact(SET_BUFFER_COUNT, data, &reply); + status_t err = reply.readInt32(); + return err; + } + virtual status_t registerBuffers(const BufferHeap& buffers) { Parcel data, reply; @@ -146,6 +156,13 @@ status_t BnSurface::onTransact( return BAD_VALUE; return reply->write(*buffer); } + case SET_BUFFER_COUNT: { + CHECK_INTERFACE(ISurface, data, reply); + int bufferCount = data.readInt32(); + status_t err = setBufferCount(bufferCount); + reply->writeInt32(err); + return NO_ERROR; + } case REGISTER_BUFFERS: { CHECK_INTERFACE(ISurface, data, reply); BufferHeap buffer; diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index d6b2375..4a98026 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -305,7 +305,6 @@ SharedBufferServer::RetireUpdate::RetireUpdate( : UpdateBase(sbb), numBuffers(numBuffers) { } ssize_t SharedBufferServer::RetireUpdate::operator()() { - // head is only written in this function, which is single-thread. int32_t head = stack.head; if (uint32_t(head) >= NUM_BUFFER_MAX) return BAD_VALUE; @@ -322,16 +321,14 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { } } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); - // update the head pointer - head = ((head+1 >= numBuffers) ? 0 : head+1); - // lock the buffer before advancing head, which automatically unlocks // the buffer we preventively locked upon entering this function + head = (head + 1) % numBuffers; android_atomic_write(stack.index[head], &stack.inUse); - // advance head + // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); - + // now that head has moved, we can increment the number of available buffers android_atomic_inc(&stack.available); return head; @@ -450,6 +447,14 @@ status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg) return stack.setDirtyRegion(buf, reg); } +status_t SharedBufferClient::setBufferCount(int bufferCount) +{ + if (uint32_t(bufferCount) >= NUM_BUFFER_MAX) + return BAD_VALUE; + mNumBuffers = bufferCount; + return NO_ERROR; +} + // ---------------------------------------------------------------------------- SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, @@ -463,6 +468,7 @@ SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, mSharedStack->reallocMask = 0; memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers)); for (int i=0 ; i<num ; i++) { + mBufferList.add(i); mSharedStack->index[i] = i; } } @@ -525,12 +531,85 @@ Region SharedBufferServer::getDirtyRegion(int buf) const return stack.getDirtyRegion(buf); } + +/* + * + * NOTE: this is not thread-safe on the server-side, meaning + * 'head' cannot move during this operation. The client-side + * can safely operate an usual. + * + */ +status_t SharedBufferServer::resize(int newNumBuffers) +{ + if (uint32_t(newNumBuffers) >= NUM_BUFFER_MAX) + return BAD_VALUE; + + // for now we're not supporting shrinking + const int numBuffers = mNumBuffers; + if (newNumBuffers < numBuffers) + return BAD_VALUE; + + SharedBufferStack& stack( *mSharedStack ); + const int extra = newNumBuffers - numBuffers; + + // read the head, make sure it's valid + int32_t head = stack.head; + if (uint32_t(head) >= NUM_BUFFER_MAX) + return BAD_VALUE; + + int base = numBuffers; + int32_t avail = stack.available; + int tail = head - avail + 1; + if (tail >= 0) { + int8_t* const index = const_cast<int8_t*>(stack.index); + const int nb = numBuffers - head; + memmove(&index[head + extra], &index[head], nb); + base = head; + // move head 'extra' ahead, this doesn't impact stack.index[head]; + stack.head = head + extra; + } + stack.available += extra; + + // fill the new free space with unused buffers + BufferList::const_iterator curr(mBufferList.free_begin()); + for (int i=0 ; i<extra ; i++) { + stack.index[base+i] = *curr++; + mBufferList.add(stack.index[base+i]); + } + + mNumBuffers = newNumBuffers; + return NO_ERROR; +} + SharedBufferStack::Statistics SharedBufferServer::getStats() const { SharedBufferStack& stack( *mSharedStack ); return stack.stats; } +// --------------------------------------------------------------------------- +status_t SharedBufferServer::BufferList::add(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (mList & mask) + return ALREADY_EXISTS; + mList |= mask; + return NO_ERROR; +} + +status_t SharedBufferServer::BufferList::remove(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (!(mList & mask)) + return NAME_NOT_FOUND; + mList &= ~mask; + return NO_ERROR; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index eee4dae..afbeafb 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -673,6 +673,27 @@ int Surface::crop(Rect const* rect) return NO_ERROR; } +int Surface::setBufferCount(int bufferCount) +{ + sp<ISurface> s(mSurface); + if (s == 0) return NO_INIT; + + // FIXME: this needs to be synchronized dequeue/queue + + status_t err = s->setBufferCount(bufferCount); + LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); + if (err == NO_ERROR) { + err = mSharedBufferClient->getStatus(); + LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err); + if (!err) { + // update our local copy of the buffer count + mSharedBufferClient->setBufferCount(bufferCount); + } + } + return err; +} + // ---------------------------------------------------------------------------- |