Merge "SharedBufferStack now can grow up to 16 buffers." into kraken
This commit is contained in:
committed by
Android (Google) Code Review
commit
2f0e6753d6
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -217,6 +217,7 @@ private:
|
||||
int connect(int api);
|
||||
int disconnect(int api);
|
||||
int crop(Rect const* rect);
|
||||
int setBufferCount(int bufferCount);
|
||||
|
||||
/*
|
||||
* private stuff...
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
Reference in New Issue
Block a user