Implement reducing the buffer count of a Surface.
Change-Id: I7f979c60c06d654aa8265002836277434bc1a64f Bug: 3095167
This commit is contained in:
parent
e9ebae24b9
commit
54cc83e8a4
|
@ -285,6 +285,8 @@ public:
|
||||||
uint32_t getTransform(int buffer) const;
|
uint32_t getTransform(int buffer) const;
|
||||||
|
|
||||||
status_t resize(int newNumBuffers);
|
status_t resize(int newNumBuffers);
|
||||||
|
status_t grow(int newNumBuffers);
|
||||||
|
status_t shrink(int newNumBuffers);
|
||||||
|
|
||||||
SharedBufferStack::Statistics getStats() const;
|
SharedBufferStack::Statistics getStats() const;
|
||||||
|
|
||||||
|
@ -346,6 +348,14 @@ private:
|
||||||
int mNumBuffers;
|
int mNumBuffers;
|
||||||
BufferList mBufferList;
|
BufferList mBufferList;
|
||||||
|
|
||||||
|
struct BuffersAvailableCondition : public ConditionBase {
|
||||||
|
int mNumBuffers;
|
||||||
|
inline BuffersAvailableCondition(SharedBufferServer* sbs,
|
||||||
|
int numBuffers);
|
||||||
|
inline bool operator()() const;
|
||||||
|
inline const char* name() const { return "BuffersAvailableCondition"; }
|
||||||
|
};
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -265,6 +265,14 @@ bool SharedBufferClient::LockCondition::operator()() const {
|
||||||
(stack.queued > 0 && stack.inUse != buf));
|
(stack.queued > 0 && stack.inUse != buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
|
||||||
|
SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
|
||||||
|
mNumBuffers(numBuffers) {
|
||||||
|
}
|
||||||
|
bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
|
||||||
|
return stack.available == mNumBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
|
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
|
||||||
|
@ -448,6 +456,7 @@ status_t SharedBufferClient::queue(int buf)
|
||||||
|
|
||||||
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
|
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
|
||||||
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
|
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +501,7 @@ status_t SharedBufferClient::setBufferCount(
|
||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
mNumBuffers = bufferCount;
|
mNumBuffers = bufferCount;
|
||||||
queued_head = (stack.head + stack.queued) % mNumBuffers;
|
queued_head = (stack.head + stack.queued) % mNumBuffers;
|
||||||
|
tail = computeTail();
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -606,17 +616,24 @@ uint32_t SharedBufferServer::getTransform(int buf) const
|
||||||
*/
|
*/
|
||||||
status_t SharedBufferServer::resize(int newNumBuffers)
|
status_t SharedBufferServer::resize(int newNumBuffers)
|
||||||
{
|
{
|
||||||
if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX)
|
if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
|
||||||
|
(unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
RWLock::AutoWLock _l(mLock);
|
RWLock::AutoWLock _l(mLock);
|
||||||
|
|
||||||
// for now we're not supporting shrinking
|
if (newNumBuffers < mNumBuffers) {
|
||||||
const int numBuffers = mNumBuffers;
|
return shrink(newNumBuffers);
|
||||||
if (newNumBuffers < numBuffers)
|
} else {
|
||||||
return BAD_VALUE;
|
return grow(newNumBuffers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t SharedBufferServer::grow(int newNumBuffers)
|
||||||
|
{
|
||||||
SharedBufferStack& stack( *mSharedStack );
|
SharedBufferStack& stack( *mSharedStack );
|
||||||
|
const int numBuffers = mNumBuffers;
|
||||||
const int extra = newNumBuffers - numBuffers;
|
const int extra = newNumBuffers - numBuffers;
|
||||||
|
|
||||||
// read the head, make sure it's valid
|
// read the head, make sure it's valid
|
||||||
|
@ -650,6 +667,54 @@ status_t SharedBufferServer::resize(int newNumBuffers)
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t SharedBufferServer::shrink(int newNumBuffers)
|
||||||
|
{
|
||||||
|
SharedBufferStack& stack( *mSharedStack );
|
||||||
|
|
||||||
|
// Shrinking is only supported if there are no buffers currently dequeued.
|
||||||
|
int32_t avail = stack.available;
|
||||||
|
int32_t queued = stack.queued;
|
||||||
|
if (avail + queued != mNumBuffers) {
|
||||||
|
return INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for any queued buffers to be displayed.
|
||||||
|
BuffersAvailableCondition condition(this, mNumBuffers);
|
||||||
|
status_t err = waitForCondition(condition);
|
||||||
|
if (err < 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset head to index 0 and make it refer to buffer 0. The same renaming
|
||||||
|
// (head -> 0) is done in the BufferManager.
|
||||||
|
int32_t head = stack.head;
|
||||||
|
int8_t* index = const_cast<int8_t*>(stack.index);
|
||||||
|
for (int8_t i = 0; i < newNumBuffers; i++) {
|
||||||
|
index[i] = i;
|
||||||
|
}
|
||||||
|
stack.head = 0;
|
||||||
|
stack.headBuf = 0;
|
||||||
|
|
||||||
|
// If one of the buffers is in use it must be the head buffer, which we are
|
||||||
|
// renaming to buffer 0.
|
||||||
|
if (stack.inUse > 0) {
|
||||||
|
stack.inUse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the buffers from the end of the list that are no longer needed.
|
||||||
|
for (int i = newNumBuffers; i < mNumBuffers; i++) {
|
||||||
|
mBufferList.remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the client to reallocate all the buffers.
|
||||||
|
reallocateAll();
|
||||||
|
|
||||||
|
mNumBuffers = newNumBuffers;
|
||||||
|
stack.available = newNumBuffers;
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
SharedBufferStack::Statistics SharedBufferServer::getStats() const
|
SharedBufferStack::Statistics SharedBufferServer::getStats() const
|
||||||
{
|
{
|
||||||
SharedBufferStack& stack( *mSharedStack );
|
SharedBufferStack& stack( *mSharedStack );
|
||||||
|
|
|
@ -855,6 +855,12 @@ int Surface::setBufferCount(int bufferCount)
|
||||||
status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
|
status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
|
||||||
LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
|
LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
|
||||||
bufferCount, strerror(-err));
|
bufferCount, strerror(-err));
|
||||||
|
|
||||||
|
if (err == NO_ERROR) {
|
||||||
|
// Clear out any references to the old buffers.
|
||||||
|
mBuffers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list);
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
SharedClient client;
|
SharedClient client;
|
||||||
SharedBufferServer s(&client, 0, 4, 0);
|
sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0));
|
||||||
|
SharedBufferServer& s(*ps);
|
||||||
SharedBufferClient c(&client, 0, 4, 0);
|
SharedBufferClient c(&client, 0, 4, 0);
|
||||||
|
|
||||||
printf("basic test 0\n");
|
printf("basic test 0\n");
|
||||||
|
@ -67,6 +68,10 @@ int main(int argc, char** argv)
|
||||||
int list3[6] = {3, 2, 1, 4, 5, 0};
|
int list3[6] = {3, 2, 1, 4, 5, 0};
|
||||||
test0(s, c, 6, list3);
|
test0(s, c, 6, list3);
|
||||||
|
|
||||||
|
c.setBufferCount(4, resize);
|
||||||
|
int list4[4] = {1, 2, 3, 0};
|
||||||
|
test0(s, c, 4, list4);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -340,8 +340,10 @@ status_t Layer::setBufferCount(int bufferCount)
|
||||||
|
|
||||||
// NOTE: lcblk->resize() is protected by an internal lock
|
// NOTE: lcblk->resize() is protected by an internal lock
|
||||||
status_t err = lcblk->resize(bufferCount);
|
status_t err = lcblk->resize(bufferCount);
|
||||||
if (err == NO_ERROR)
|
if (err == NO_ERROR) {
|
||||||
mBufferManager.resize(bufferCount);
|
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
|
||||||
|
mBufferManager.resize(bufferCount, mFlinger, dpy);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -774,9 +776,52 @@ Layer::BufferManager::~BufferManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Layer::BufferManager::resize(size_t size)
|
status_t Layer::BufferManager::resize(size_t size,
|
||||||
|
const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(mLock);
|
Mutex::Autolock _l(mLock);
|
||||||
|
|
||||||
|
if (size < mNumBuffers) {
|
||||||
|
// Move the active texture into slot 0
|
||||||
|
BufferData activeBufferData = mBufferData[mActiveBuffer];
|
||||||
|
mBufferData[mActiveBuffer] = mBufferData[0];
|
||||||
|
mBufferData[0] = activeBufferData;
|
||||||
|
mActiveBuffer = 0;
|
||||||
|
|
||||||
|
// Free the buffers that are no longer needed.
|
||||||
|
for (size_t i = size; i < mNumBuffers; i++) {
|
||||||
|
mBufferData[i].buffer = 0;
|
||||||
|
|
||||||
|
// Create a message to destroy the textures on SurfaceFlinger's GL
|
||||||
|
// thread.
|
||||||
|
class MessageDestroyTexture : public MessageBase {
|
||||||
|
Image mTexture;
|
||||||
|
EGLDisplay mDpy;
|
||||||
|
public:
|
||||||
|
MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
|
||||||
|
: mTexture(texture), mDpy(dpy) { }
|
||||||
|
virtual bool handler() {
|
||||||
|
status_t err = Layer::BufferManager::destroyTexture(
|
||||||
|
&mTexture, mDpy);
|
||||||
|
LOGE_IF(err<0, "error destroying texture: %d (%s)",
|
||||||
|
mTexture.name, strerror(-err));
|
||||||
|
return true; // XXX: err == 0; ????
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageDestroyTexture *msg = new MessageDestroyTexture(
|
||||||
|
mBufferData[i].texture, dpy);
|
||||||
|
|
||||||
|
// Don't allow this texture to be cleaned up by
|
||||||
|
// BufferManager::destroy.
|
||||||
|
mBufferData[i].texture.name = -1U;
|
||||||
|
mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
|
||||||
|
|
||||||
|
// Post the message to the SurfaceFlinger object.
|
||||||
|
flinger->postMessageAsync(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mNumBuffers = size;
|
mNumBuffers = size;
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,8 @@ private:
|
||||||
sp<GraphicBuffer> detachBuffer(size_t index);
|
sp<GraphicBuffer> detachBuffer(size_t index);
|
||||||
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
|
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
|
||||||
// resize the number of active buffers
|
// resize the number of active buffers
|
||||||
status_t resize(size_t size);
|
status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
|
||||||
|
EGLDisplay dpy);
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
// must be called from GL thread
|
// must be called from GL thread
|
||||||
|
|
Loading…
Reference in New Issue