am 2f0e6753
: Merge "SharedBufferStack now can grow up to 16 buffers." into kraken
This commit is contained in:
@ -129,7 +129,7 @@ public:
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// 4 KB max
|
// 32 KB max
|
||||||
class SharedClient
|
class SharedClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -166,7 +166,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
SharedClient* const mSharedClient;
|
SharedClient* const mSharedClient;
|
||||||
SharedBufferStack* const mSharedStack;
|
SharedBufferStack* const mSharedStack;
|
||||||
const int mNumBuffers;
|
int mNumBuffers;
|
||||||
const int mIdentity;
|
const int mIdentity;
|
||||||
int32_t computeTail() const;
|
int32_t computeTail() const;
|
||||||
|
|
||||||
@ -217,6 +217,7 @@ public:
|
|||||||
bool needNewBuffer(int buffer) const;
|
bool needNewBuffer(int buffer) const;
|
||||||
status_t setDirtyRegion(int buffer, const Region& reg);
|
status_t setDirtyRegion(int buffer, const Region& reg);
|
||||||
status_t setCrop(int buffer, const Rect& reg);
|
status_t setCrop(int buffer, const Rect& reg);
|
||||||
|
status_t setBufferCount(int bufferCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct Condition;
|
friend struct Condition;
|
||||||
@ -269,13 +270,61 @@ public:
|
|||||||
status_t reallocate();
|
status_t reallocate();
|
||||||
status_t assertReallocate(int buffer);
|
status_t assertReallocate(int buffer);
|
||||||
int32_t getQueuedCount() const;
|
int32_t getQueuedCount() const;
|
||||||
|
|
||||||
Region getDirtyRegion(int buffer) const;
|
Region getDirtyRegion(int buffer) const;
|
||||||
|
|
||||||
|
status_t resize(int newNumBuffers);
|
||||||
|
|
||||||
SharedBufferStack::Statistics getStats() const;
|
SharedBufferStack::Statistics getStats() const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
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 {
|
struct UnlockUpdate : public UpdateBase {
|
||||||
const int lockedBuffer;
|
const int lockedBuffer;
|
||||||
inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
|
inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
|
||||||
|
@ -47,12 +47,14 @@ protected:
|
|||||||
POST_BUFFER, // one-way transaction
|
POST_BUFFER, // one-way transaction
|
||||||
CREATE_OVERLAY,
|
CREATE_OVERLAY,
|
||||||
REQUEST_BUFFER,
|
REQUEST_BUFFER,
|
||||||
|
SET_BUFFER_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_META_INTERFACE(Surface);
|
DECLARE_META_INTERFACE(Surface);
|
||||||
|
|
||||||
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0;
|
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0;
|
||||||
|
virtual status_t setBufferCount(int bufferCount) = 0;
|
||||||
|
|
||||||
class BufferHeap {
|
class BufferHeap {
|
||||||
public:
|
public:
|
||||||
|
@ -217,6 +217,7 @@ private:
|
|||||||
int connect(int api);
|
int connect(int api);
|
||||||
int disconnect(int api);
|
int disconnect(int api);
|
||||||
int crop(Rect const* rect);
|
int crop(Rect const* rect);
|
||||||
|
int setBufferCount(int bufferCount);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* private stuff...
|
* private stuff...
|
||||||
|
@ -208,6 +208,30 @@ void Layer::onDraw(const Region& clip) const
|
|||||||
drawWithOpenGL(clip, tex);
|
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> Layer::requestBuffer(int index, int usage)
|
||||||
{
|
{
|
||||||
sp<GraphicBuffer> buffer;
|
sp<GraphicBuffer> buffer;
|
||||||
@ -642,6 +666,16 @@ sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
|
|||||||
return buffer;
|
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;
|
uint32_t getEffectiveUsage(uint32_t usage) const;
|
||||||
|
|
||||||
sp<GraphicBuffer> requestBuffer(int index, int usage);
|
sp<GraphicBuffer> requestBuffer(int index, int usage);
|
||||||
|
status_t setBufferCount(int bufferCount);
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
class SurfaceLayer : public LayerBaseClient::Surface {
|
class SurfaceLayer : public LayerBaseClient::Surface {
|
||||||
@ -98,6 +99,7 @@ private:
|
|||||||
~SurfaceLayer();
|
~SurfaceLayer();
|
||||||
private:
|
private:
|
||||||
virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
|
virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
|
||||||
|
virtual status_t setBufferCount(int bufferCount);
|
||||||
sp<Layer> getOwner() const {
|
sp<Layer> getOwner() const {
|
||||||
return static_cast<Layer*>(Surface::getOwner().get());
|
return static_cast<Layer*>(Surface::getOwner().get());
|
||||||
}
|
}
|
||||||
|
@ -621,6 +621,11 @@ sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
|
||||||
|
{
|
||||||
|
return INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
status_t LayerBaseClient::Surface::registerBuffers(
|
status_t LayerBaseClient::Surface::registerBuffers(
|
||||||
const ISurface::BufferHeap& buffers)
|
const ISurface::BufferHeap& buffers)
|
||||||
{
|
{
|
||||||
|
@ -302,6 +302,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
|
virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
|
||||||
|
virtual status_t setBufferCount(int bufferCount);
|
||||||
|
|
||||||
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
||||||
virtual void postBuffer(ssize_t offset);
|
virtual void postBuffer(ssize_t offset);
|
||||||
virtual void unregisterBuffers();
|
virtual void unregisterBuffers();
|
||||||
|
@ -83,6 +83,16 @@ public:
|
|||||||
return buffer;
|
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)
|
virtual status_t registerBuffers(const BufferHeap& buffers)
|
||||||
{
|
{
|
||||||
Parcel data, reply;
|
Parcel data, reply;
|
||||||
@ -146,6 +156,13 @@ status_t BnSurface::onTransact(
|
|||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
return reply->write(*buffer);
|
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: {
|
case REGISTER_BUFFERS: {
|
||||||
CHECK_INTERFACE(ISurface, data, reply);
|
CHECK_INTERFACE(ISurface, data, reply);
|
||||||
BufferHeap buffer;
|
BufferHeap buffer;
|
||||||
|
@ -305,7 +305,6 @@ SharedBufferServer::RetireUpdate::RetireUpdate(
|
|||||||
: UpdateBase(sbb), numBuffers(numBuffers) {
|
: UpdateBase(sbb), numBuffers(numBuffers) {
|
||||||
}
|
}
|
||||||
ssize_t SharedBufferServer::RetireUpdate::operator()() {
|
ssize_t SharedBufferServer::RetireUpdate::operator()() {
|
||||||
// head is only written in this function, which is single-thread.
|
|
||||||
int32_t head = stack.head;
|
int32_t head = stack.head;
|
||||||
if (uint32_t(head) >= NUM_BUFFER_MAX)
|
if (uint32_t(head) >= NUM_BUFFER_MAX)
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
@ -322,16 +321,14 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() {
|
|||||||
}
|
}
|
||||||
} while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
|
} 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
|
// lock the buffer before advancing head, which automatically unlocks
|
||||||
// the buffer we preventively locked upon entering this function
|
// the buffer we preventively locked upon entering this function
|
||||||
|
head = (head + 1) % numBuffers;
|
||||||
android_atomic_write(stack.index[head], &stack.inUse);
|
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);
|
android_atomic_write(head, &stack.head);
|
||||||
|
|
||||||
// now that head has moved, we can increment the number of available buffers
|
// now that head has moved, we can increment the number of available buffers
|
||||||
android_atomic_inc(&stack.available);
|
android_atomic_inc(&stack.available);
|
||||||
return head;
|
return head;
|
||||||
@ -450,6 +447,14 @@ status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
|
|||||||
return stack.setDirtyRegion(buf, 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,
|
SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
|
||||||
@ -463,6 +468,7 @@ SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
|
|||||||
mSharedStack->reallocMask = 0;
|
mSharedStack->reallocMask = 0;
|
||||||
memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
|
memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
|
||||||
for (int i=0 ; i<num ; i++) {
|
for (int i=0 ; i<num ; i++) {
|
||||||
|
mBufferList.add(i);
|
||||||
mSharedStack->index[i] = i;
|
mSharedStack->index[i] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,12 +531,85 @@ Region SharedBufferServer::getDirtyRegion(int buf) const
|
|||||||
return stack.getDirtyRegion(buf);
|
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::Statistics SharedBufferServer::getStats() const
|
||||||
{
|
{
|
||||||
SharedBufferStack& stack( *mSharedStack );
|
SharedBufferStack& stack( *mSharedStack );
|
||||||
return stack.stats;
|
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
|
}; // namespace android
|
||||||
|
@ -673,6 +673,27 @@ int Surface::crop(Rect const* rect)
|
|||||||
return NO_ERROR;
|
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