summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-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
7 files changed, 166 insertions, 6 deletions
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;
+}
+
// ----------------------------------------------------------------------------