Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ba398df authored by Jamie Gennis's avatar Jamie Gennis Committed by Android (Google) Code Review
Browse files

Merge "Implement reducing the buffer count of a Surface."

parents 8ebed10a 54cc83e8
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -285,6 +285,8 @@ public:
    uint32_t getTransform(int buffer) const;

    status_t resize(int newNumBuffers);
    status_t grow(int newNumBuffers);
    status_t shrink(int newNumBuffers);

    SharedBufferStack::Statistics getStats() const;
    
@@ -346,6 +348,14 @@ private:
    int mNumBuffers;
    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 {
        const int lockedBuffer;
        inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
+70 −5
Original line number Diff line number Diff line
@@ -265,6 +265,14 @@ bool SharedBufferClient::LockCondition::operator()() const {
            (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)
@@ -448,6 +456,7 @@ status_t SharedBufferClient::queue(int buf)

    const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
    stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);

    return err;
}

@@ -492,6 +501,7 @@ status_t SharedBufferClient::setBufferCount(
    if (err == NO_ERROR) {
        mNumBuffers = bufferCount;
        queued_head = (stack.head + stack.queued) % mNumBuffers;
        tail = computeTail();
    }
    return err;
}
@@ -606,17 +616,24 @@ uint32_t SharedBufferServer::getTransform(int buf) const
 */
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;
    }

    RWLock::AutoWLock _l(mLock);

    // for now we're not supporting shrinking
    const int numBuffers = mNumBuffers;
    if (newNumBuffers < numBuffers)
        return BAD_VALUE;
    if (newNumBuffers < mNumBuffers) {
        return shrink(newNumBuffers);
    } else {
        return grow(newNumBuffers);
    }
}

status_t SharedBufferServer::grow(int newNumBuffers)
{
    SharedBufferStack& stack( *mSharedStack );
    const int numBuffers = mNumBuffers;
    const int extra = newNumBuffers - numBuffers;

    // read the head, make sure it's valid
@@ -650,6 +667,54 @@ status_t SharedBufferServer::resize(int newNumBuffers)
    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& stack( *mSharedStack );
+6 −0
Original line number Diff line number Diff line
@@ -855,6 +855,12 @@ int Surface::setBufferCount(int bufferCount)
    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
            bufferCount, strerror(-err));

    if (err == NO_ERROR) {
        // Clear out any references to the old buffers.
        mBuffers.clear();
    }

    return err;
}

+6 −1
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@ void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list);
int main(int argc, char** argv)
{
    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);

    printf("basic test 0\n");
@@ -67,6 +68,10 @@ int main(int argc, char** argv)
    int list3[6] = {3, 2, 1, 4, 5, 0};
    test0(s, c, 6, list3);

    c.setBufferCount(4, resize);
    int list4[4] = {1, 2, 3, 0};
    test0(s, c, 4, list4);

    return 0;
}

+48 −3
Original line number Diff line number Diff line
@@ -340,8 +340,10 @@ status_t Layer::setBufferCount(int bufferCount)

    // NOTE: lcblk->resize() is protected by an internal lock
    status_t err = lcblk->resize(bufferCount);
    if (err == NO_ERROR)
        mBufferManager.resize(bufferCount);
    if (err == NO_ERROR) {
        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
        mBufferManager.resize(bufferCount, mFlinger, dpy);
    }

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

    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;
    return NO_ERROR;
}
Loading