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

Commit 4f9c275b authored by Jim Shargo's avatar Jim Shargo
Browse files

libgui: Add unlimited slot support to Surfaces and Consumers

Surfaces can now use `setMaxDequeuedBufferCount` with any value when the
consumer supports it to give themselves an essentially unlimited number
of buffers to use.

ConsumerBase and its libgui children have been updated to allow for
unlimited buffer slots by default (meaning all users opt into this
automatically), and their implementations have been updated to track the
new variable slot limit.

This is part of go/warren-buffers.

Bug: 341359185
Flag: com.android.graphics.libgui.flags.wb_unlimited_slots
Test: new tests, old tests
Change-Id: I374aa204a2e42a17d95c6e0ffaef2c2caaa9c963
parent 2e614a49
Loading
Loading
Loading
Loading
+73 −6
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@

#include <private/gui/ComposerService.h>

#include <ui/BufferQueueDefs.h>

#include <log/log.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -59,7 +61,11 @@ static int32_t createProcessUniqueId() {
    return android_atomic_inc(&globalCounter);
}

ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp)
      :
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mAbandoned(false),
        mConsumer(bufferQueue),
        mPrevFinalReleaseFence(Fence::NO_FENCE) {
@@ -68,7 +74,12 @@ ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool c

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
ConsumerBase::ConsumerBase(bool controlledByApp, bool consumerIsSurfaceFlinger)
      : mAbandoned(false), mPrevFinalReleaseFence(Fence::NO_FENCE) {
      :
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mAbandoned(false),
        mPrevFinalReleaseFence(Fence::NO_FENCE) {
    sp<IGraphicBufferProducer> producer;
    BufferQueue::createBufferQueue(&producer, &mConsumer, consumerIsSurfaceFlinger);
    mSurface = sp<Surface>::make(producer, controlledByApp);
@@ -77,7 +88,11 @@ ConsumerBase::ConsumerBase(bool controlledByApp, bool consumerIsSurfaceFlinger)

ConsumerBase::ConsumerBase(const sp<IGraphicBufferProducer>& producer,
                           const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp)
      : mAbandoned(false),
      :
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mAbandoned(false),
        mConsumer(consumer),
        mSurface(sp<Surface>::make(producer, controlledByApp)),
        mPrevFinalReleaseFence(Fence::NO_FENCE) {
@@ -101,9 +116,16 @@ void ConsumerBase::initialize(bool controlledByApp) {
    if (err != NO_ERROR) {
        CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
                strerror(-err), err);
    } else {
        return;
    }

    mConsumer->setConsumerName(mName);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    if (err = mConsumer->allowUnlimitedSlots(true); err != NO_ERROR) {
        CB_LOGE("ConsumerBase: error marking as allowed to have unlimited slots: %s (%d)",
                strerror(-err), err);
    }
#endif
}

ConsumerBase::~ConsumerBase() {
@@ -130,7 +152,11 @@ int ConsumerBase::getSlotForBufferLocked(const sp<GraphicBuffer>& buffer) {
    }

    uint64_t id = buffer->getId();
    for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int i = 0; i < (int)mSlots.size(); ++i) {
#else
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
#endif
        auto& slot = mSlots[i];
        if (slot.mGraphicBuffer && slot.mGraphicBuffer->getId() == id) {
            return i;
@@ -242,6 +268,15 @@ void ConsumerBase::onBuffersReleased() {
        return;
    }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    std::vector<bool> mask;
    mConsumer->getReleasedBuffersExtended(&mask);
    for (size_t i = 0; i < mSlots.size(); i++) {
        if (mask[i]) {
            freeBufferLocked(i);
        }
    }
#else
    uint64_t mask = 0;
    mConsumer->getReleasedBuffers(&mask);
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
@@ -249,6 +284,7 @@ void ConsumerBase::onBuffersReleased() {
            freeBufferLocked(i);
        }
    }
#endif
}

void ConsumerBase::onSidebandStreamChanged() {
@@ -281,7 +317,11 @@ void ConsumerBase::abandonLocked() {
        CB_LOGE("abandonLocked: ConsumerBase is abandoned!");
        return;
    }
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int i = 0; i < (int)mSlots.size(); ++i) {
#else
    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
#endif
        freeBufferLocked(i);
    }
    // disconnect from the BufferQueue
@@ -398,6 +438,15 @@ status_t ConsumerBase::setMaxBufferCount(int bufferCount) {
        CB_LOGE("setMaxBufferCount: ConsumerBase is abandoned!");
        return NO_INIT;
    }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    if (status_t err = mConsumer->allowUnlimitedSlots(false); err != NO_ERROR) {
        CB_LOGE("ConsumerBase: error marking as not allowed to have unlimited slots: %s (%d)",
                strerror(-err), err);
        return err;
    }
#endif

    return mConsumer->setMaxBufferCount(bufferCount);
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
@@ -459,6 +508,15 @@ status_t ConsumerBase::discardFreeBuffers() {
    if (err != OK) {
        return err;
    }
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    std::vector<bool> mask;
    mConsumer->getReleasedBuffersExtended(&mask);
    for (int i = 0; i < (int)mSlots.size(); i++) {
        if (mask[i]) {
            freeBufferLocked(i);
        }
    }
#else
    uint64_t mask;
    mConsumer->getReleasedBuffers(&mask);
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
@@ -466,6 +524,8 @@ status_t ConsumerBase::discardFreeBuffers() {
            freeBufferLocked(i);
        }
    }
#endif

    return OK;
}

@@ -607,6 +667,9 @@ status_t ConsumerBase::releaseBufferLocked(
    // buffer on the same slot), the buffer producer is definitely no longer
    // tracking it.
    if (!stillTracking(slot, graphicBuffer)) {
        CB_LOGV("releaseBufferLocked: Not tracking, exiting without calling releaseBuffer for "
                "slot=%d/%" PRIu64,
                slot, mSlots[slot].mFrameNumber);
        return OK;
    }

@@ -626,7 +689,11 @@ status_t ConsumerBase::releaseBufferLocked(

bool ConsumerBase::stillTracking(int slot,
        const sp<GraphicBuffer> graphicBuffer) {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    if (slot < 0 || slot >= (int)mSlots.size()) {
#else
    if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
#endif
        return false;
    }
    return (mSlots[slot].mGraphicBuffer != nullptr &&
+43 −21
Original line number Diff line number Diff line
@@ -119,6 +119,9 @@ GLConsumer::GLConsumer(uint32_t tex, uint32_t texTarget, bool useFenceSync, bool
        mTexTarget(texTarget),
        mEglDisplay(EGL_NO_DISPLAY),
        mEglContext(EGL_NO_CONTEXT),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mEglSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
        mAttached(true) {
    GLC_LOGV("GLConsumer");
@@ -129,9 +132,9 @@ GLConsumer::GLConsumer(uint32_t tex, uint32_t texTarget, bool useFenceSync, bool
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)

GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
        uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
    ConsumerBase(bq, isControlledByApp),
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texTarget,
                       bool useFenceSync, bool isControlledByApp)
      : ConsumerBase(bq, isControlledByApp),
        mCurrentCrop(Rect::EMPTY_RECT),
        mCurrentTransform(0),
        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -147,9 +150,11 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
        mTexTarget(texTarget),
        mEglDisplay(EGL_NO_DISPLAY),
        mEglContext(EGL_NO_CONTEXT),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mEglSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)
{
        mAttached(true) {
    GLC_LOGV("GLConsumer");

    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
@@ -176,6 +181,9 @@ GLConsumer::GLConsumer(uint32_t texTarget, bool useFenceSync, bool isControlledB
        mTexTarget(texTarget),
        mEglDisplay(EGL_NO_DISPLAY),
        mEglContext(EGL_NO_CONTEXT),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mEglSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
        mAttached(false) {
    GLC_LOGV("GLConsumer");
@@ -204,6 +212,9 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
        mTexTarget(texTarget),
        mEglDisplay(EGL_NO_DISPLAY),
        mEglContext(EGL_NO_CONTEXT),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mEglSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
        mAttached(false) {
    GLC_LOGV("GLConsumer");
@@ -395,6 +406,17 @@ status_t GLConsumer::acquireBufferLocked(BufferItem *item,
    return NO_ERROR;
}

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
void GLConsumer::onSlotCountChanged(int slotCount) {
    ConsumerBase::onSlotCountChanged(slotCount);

    Mutex::Autolock lock(mMutex);
    if (slotCount > (int)mEglSlots.size()) {
        mEglSlots.resize(slotCount);
    }
}
#endif

status_t GLConsumer::releaseBufferLocked(int buf,
        sp<GraphicBuffer> graphicBuffer,
        EGLDisplay display, EGLSyncKHR eglFence) {
+3 −1
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
    return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) +
            sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount) +
            sizeof(result);
            sizeof(result) + sizeof(isSlotExpansionAllowed);
}
size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
    return minFlattenedSize() + frameTimestamps.getFlattenedSize();
@@ -152,6 +152,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
    FlattenableUtils::write(buffer, size, nextFrameNumber);
    FlattenableUtils::write(buffer, size, bufferReplaced);
    FlattenableUtils::write(buffer, size, maxBufferCount);
    FlattenableUtils::write(buffer, size, isSlotExpansionAllowed);

    status_t result = frameTimestamps.flatten(buffer, size, fds, count);
    if (result != NO_ERROR) {
@@ -175,6 +176,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
    FlattenableUtils::read(buffer, size, nextFrameNumber);
    FlattenableUtils::read(buffer, size, bufferReplaced);
    FlattenableUtils::read(buffer, size, maxBufferCount);
    FlattenableUtils::read(buffer, size, isSlotExpansionAllowed);

    status_t result = frameTimestamps.unflatten(buffer, size, fds, count);
    if (result != NO_ERROR) {
+71 −5
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <utils/NativeHandle.h>
#include <utils/Trace.h>

#include <ui/BufferQueueDefs.h>
#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -98,7 +99,10 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll
      : mGraphicBufferProducer(bufferProducer),
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
        mSurfaceDeathListener(nullptr),
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
#endif
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mSlots(NUM_BUFFER_SLOTS),
#endif
        mCrop(Rect::EMPTY_RECT),
        mBufferAge(0),
        mGenerationNumber(0),
@@ -192,7 +196,7 @@ void Surface::allocateBuffers() {
status_t Surface::allowAllocation(bool allowAllocation) {
    return mGraphicBufferProducer->allowAllocation(allowAllocation);
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
#endif

status_t Surface::setGenerationNumber(uint32_t generation) {
    status_t result = mGraphicBufferProducer->setGenerationNumber(generation);
@@ -658,7 +662,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
        return result;
    }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    if (buf < 0 || buf >= (int)mSlots.size()) {
#else
    if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
#endif
        ALOGE("dequeueBuffer: IGraphicBufferProducer returned invalid slot number %d", buf);
        android_errorWriteLog(0x534e4554, "36991414"); // SafetyNet logging
        return FAILED_TRANSACTION;
@@ -757,7 +765,11 @@ status_t Surface::detachBuffer(const sp<GraphicBuffer>& buffer) {
    Mutex::Autolock lock(mMutex);

    uint64_t bufferId = buffer->getId();
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int slot = 0; slot < (int)mSlots.size(); ++slot) {
#else
    for (int slot = 0; slot < Surface::NUM_BUFFER_SLOTS; ++slot) {
#endif
        auto& bufferSlot = mSlots[slot];
        if (bufferSlot.buffer != nullptr && bufferSlot.buffer->getId() == bufferId) {
            bufferSlot.buffer = nullptr;
@@ -840,7 +852,11 @@ int Surface::dequeueBuffers(std::vector<BatchBuffer>* buffers) {
            return output.result;
        }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        if (output.slot < 0 || output.slot >= (int)mSlots.size()) {
#else
        if (output.slot < 0 || output.slot >= NUM_BUFFER_SLOTS) {
#endif
            mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs);
            ALOGE("%s: IGraphicBufferProducer returned invalid slot number %d",
                    __FUNCTION__, output.slot);
@@ -1027,7 +1043,11 @@ int Surface::getSlotFromBufferLocked(
        return BAD_VALUE;
    }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int i = 0; i < (int)mSlots.size(); i++) {
#else
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
#endif
        if (mSlots[i].buffer != nullptr &&
                mSlots[i].buffer->handle == buffer->handle) {
            return i;
@@ -2094,6 +2114,9 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu
        mDefaultHeight = output.height;
        mNextFrameNumber = output.nextFrameNumber;
        mMaxBufferCount = output.maxBufferCount;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        mIsSlotExpansionAllowed = output.isSlotExpansionAllowed;
#endif

        // Ignore transform hint if sticky transform is set or transform to display inverse flag is
        // set. Transform hint should be ignored if the client is expected to always submit buffers
@@ -2190,7 +2213,11 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
        *outFence = Fence::NO_FENCE;
    }

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int i = 0; i < (int)mSlots.size(); i++) {
#else
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
#endif
        if (mSlots[i].buffer != nullptr &&
                mSlots[i].buffer->getId() == buffer->getId()) {
            if (mReportRemovedBuffers) {
@@ -2292,8 +2319,35 @@ int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
    ALOGV("Surface::setMaxDequeuedBufferCount");
    Mutex::Autolock lock(mMutex);

    status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
            maxDequeuedBuffers);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    if (maxDequeuedBuffers > BufferQueueDefs::NUM_BUFFER_SLOTS && !mIsSlotExpansionAllowed) {
        return BAD_VALUE;
    }

    int minUndequeuedBuffers = 0;
    status_t err = mGraphicBufferProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
                                                 &minUndequeuedBuffers);
    if (err != OK) {
        ALOGE("IGraphicBufferProducer::query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS) returned %s",
              strerror(-err));
        return err;
    }

    if (maxDequeuedBuffers > (int)mSlots.size()) {
        int newSlotCount = minUndequeuedBuffers + maxDequeuedBuffers;
        err = mGraphicBufferProducer->extendSlotCount(newSlotCount);
        if (err != OK) {
            ALOGE("IGraphicBufferProducer::extendSlotCount(%d) returned %s", newSlotCount,
                  strerror(-err));
            return err;
        }

        mSlots.resize(newSlotCount);
    }
    err = mGraphicBufferProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
#else
    status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
#endif
    ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) "
            "returned %s", maxDequeuedBuffers, strerror(-err));

@@ -2501,7 +2555,11 @@ void Surface::freeAllBuffers() {
        ALOGE("%s: %zu buffers were freed while being dequeued!",
                __FUNCTION__, mDequeuedSlots.size());
    }
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    for (int i = 0; i < (int)mSlots.size(); i++) {
#else
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
#endif
        mSlots[i].buffer = nullptr;
    }
}
@@ -2510,7 +2568,11 @@ status_t Surface::getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
        std::vector<sp<GraphicBuffer>>* outBuffers) {
    ALOGV("Surface::getAndFlushBuffersFromSlots");
    for (int32_t i : slots) {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
        if (i < 0 || i >= (int)mSlots.size()) {
#else
        if (i < 0 || i >= NUM_BUFFER_SLOTS) {
#endif
            ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i);
            return BAD_VALUE;
        }
@@ -2670,7 +2732,11 @@ status_t Surface::lock(
            newDirtyRegion.set(bounds);
            mDirtyRegion.clear();
            Mutex::Autolock lock(mMutex);
            for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
            for (int i = 0; i < (int)mSlots.size(); i++) {
#else
            for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
#endif
                mSlots[i].dirtyRegion.clear();
            }
        }
+7 −1
Original line number Diff line number Diff line
@@ -266,6 +266,9 @@ protected:
    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
            uint64_t maxFrameNumber = 0) override;

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    virtual void onSlotCountChanged(int slotCount) override;
#endif
    // releaseBufferLocked overrides the ConsumerBase method to update the
    // mEglSlots array in addition to the ConsumerBase.
    virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer,
@@ -496,8 +499,11 @@ private:
    // slot that has not yet been used. The buffer allocated to a slot will also
    // be replaced if the requested buffer usage or geometry differs from that
    // of the buffer allocated to a slot.
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS)
    std::vector<EglSlot> mEglSlots;
#else
    EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];

#endif
    // mCurrentTexture is the buffer slot index of the buffer that is currently
    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
    // indicating that no buffer slot is currently bound to the texture. Note,
Loading