Merge "SharedBufferStack now can grow up to 16 buffers." into kraken

This commit is contained in:
Mathias Agopian
2010-05-12 17:36:46 -07:00
committed by Android (Google) Code Review
10 changed files with 221 additions and 9 deletions

View File

@ -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);

View File

@ -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:

View File

@ -217,6 +217,7 @@ private:
int connect(int api);
int disconnect(int api);
int crop(Rect const* rect);
int setBufferCount(int bufferCount);
/*
* private stuff...

View File

@ -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;
}
// ---------------------------------------------------------------------------

View File

@ -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());
}

View File

@ -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)
{

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;
}
// ----------------------------------------------------------------------------