summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/private/surfaceflinger/SharedBufferStack.h55
-rw-r--r--include/surfaceflinger/ISurface.h2
-rw-r--r--include/surfaceflinger/Surface.h1
-rw-r--r--libs/surfaceflinger/Layer.cpp34
-rw-r--r--libs/surfaceflinger/Layer.h2
-rw-r--r--libs/surfaceflinger/LayerBase.cpp5
-rw-r--r--libs/surfaceflinger/LayerBase.h2
-rw-r--r--libs/surfaceflinger_client/ISurface.cpp17
-rw-r--r--libs/surfaceflinger_client/SharedBufferStack.cpp91
-rw-r--r--libs/surfaceflinger_client/Surface.cpp21
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;
+}
+
// ----------------------------------------------------------------------------