diff options
30 files changed, 1121 insertions, 86 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index b0f6e69115..f1374e23fd 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -108,6 +108,15 @@ void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t } #endif +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +void BufferQueue::ProxyConsumerListener::onSlotCountChanged(int slotCount) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onSlotCountChanged(slotCount); + } +} +#endif + void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 9855b5bca4..f0125868ae 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -341,9 +341,9 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { return BAD_VALUE; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount) { + BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isAcquired()) { BQ_LOGE("detachBuffer: slot %d is not owned by the consumer " @@ -483,10 +483,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == nullptr) { - BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, - releaseFence.get()); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount) { + BQ_LOGE("releaseBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount); + return BAD_VALUE; + } + if (releaseFence == nullptr) { + BQ_LOGE("releaseBuffer: slot %d fence %p NULL", slot, releaseFence.get()); return BAD_VALUE; } @@ -515,6 +518,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, { // Autolock scope std::lock_guard<std::mutex> lock(mCore->mMutex); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount || releaseFence == nullptr) { + BQ_LOGE("releaseBuffer: slot %d out of range [0, %d) or fence %p NULL", slot, + totalSlotCount, releaseFence.get()); + return BAD_VALUE; + } + // If the frame number has changed because the buffer has been reallocated, // we can ignore this releaseBuffer for the old buffer. // Ignore this for the shared buffer where the frame number can easily @@ -661,6 +671,43 @@ status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +status_t BufferQueueConsumer::getReleasedBuffersExtended(std::vector<bool>* outSlotMask) { + ATRACE_CALL(); + + if (outSlotMask == nullptr) { + BQ_LOGE("getReleasedBuffersExtended: outSlotMask may not be NULL"); + return BAD_VALUE; + } + + std::lock_guard<std::mutex> lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("getReleasedBuffersExtended: BufferQueue has been abandoned"); + return NO_INIT; + } + + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + outSlotMask->resize(totalSlotCount); + for (int s = 0; s < totalSlotCount; ++s) { + (*outSlotMask)[s] = !mSlots[s].mAcquireCalled; + } + + // Remove from the mask queued buffers for which acquire has been called, + // since the consumer will not receive their buffer addresses and so must + // retain their cached information + BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); + while (current != mCore->mQueue.end()) { + if (current->mAcquireCalled) { + (*outSlotMask)[current->mSlot] = false; + } + ++current; + } + + return NO_ERROR; +} +#endif + status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) { ATRACE_CALL(); @@ -679,6 +726,28 @@ status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +status_t BufferQueueConsumer::allowUnlimitedSlots(bool allowUnlimitedSlots) { + ATRACE_CALL(); + BQ_LOGV("allowUnlimitedSlots: %d", allowUnlimitedSlots); + std::lock_guard<std::mutex> lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("allowUnlimitedSlots: BufferQueue has been abandoned"); + return NO_INIT; + } + + if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("allowUnlimitedSlots: BufferQueue already connected"); + return INVALID_OPERATION; + } + + mCore->mAllowExtendedSlotCount = allowUnlimitedSlots; + + return OK; +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { ATRACE_CALL(); @@ -718,16 +787,23 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( int maxAcquiredBuffers) { ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers); - if (maxAcquiredBuffers < 1 || - maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { - BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - sp<IConsumerListener> listener; { // Autolock scope std::unique_lock<std::mutex> lock(mCore->mMutex); + + // We reserve two slots in order to guarantee that the producer and + // consumer can run asynchronously. + int maxMaxAcquiredBuffers = +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + mCore->getTotalSlotCountLocked() - 2; +#else + BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS; +#endif + if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > maxMaxAcquiredBuffers) { + BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", maxAcquiredBuffers); + return BAD_VALUE; + } + mCore->waitWhileAllocatingLocked(lock); if (mCore->mIsAbandoned) { diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 5a093995b4..6c79904475 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -38,6 +38,8 @@ #include <system/window.h> +#include <ui/BufferQueueDefs.h> + namespace android { // Macros for include BufferQueueCore information in log messages @@ -97,7 +99,11 @@ BufferQueueCore::BufferQueueCore() mConnectedProducerListener(), mBufferReleasedCbEnabled(false), mBufferAttachedCbEnabled(false), +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS), +#else mSlots(), +#endif mQueue(), mFreeSlots(), mFreeBuffers(), @@ -111,6 +117,9 @@ BufferQueueCore::BufferQueueCore() mDefaultWidth(1), mDefaultHeight(1), mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + mAllowExtendedSlotCount(false), +#endif mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), mMaxAcquiredBufferCount(1), mMaxDequeuedBufferCount(1), @@ -221,6 +230,14 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const } } +int BufferQueueCore::getTotalSlotCountLocked() const { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + return mAllowExtendedSlotCount ? mMaxBufferCount : BufferQueueDefs::NUM_BUFFER_SLOTS; +#else + return BufferQueueDefs::NUM_BUFFER_SLOTS; +#endif +} + int BufferQueueCore::getMinUndequeuedBufferCountLocked() const { // If dequeueBuffer is allowed to error out, we don't have to add an // extra buffer. @@ -253,6 +270,26 @@ int BufferQueueCore::getMaxBufferCountLocked() const { return maxBufferCount; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +status_t BufferQueueCore::extendSlotCountLocked(int size) { + int previousSize = (int)mSlots.size(); + if (previousSize > size) { + return BAD_VALUE; + } + if (previousSize == size) { + return NO_ERROR; + } + + mSlots.resize(size); + for (int i = previousSize; i < size; i++) { + mUnusedSlots.push_back(i); + } + + mMaxBufferCount = size; + return NO_ERROR; +} +#endif + void BufferQueueCore::clearBufferSlotLocked(int slot) { BQ_LOGV("clearBufferSlotLocked: slot %d", slot); @@ -383,7 +420,7 @@ void BufferQueueCore::notifyBufferReleased() const { void BufferQueueCore::validateConsistencyLocked() const { static const useconds_t PAUSE_TIME = 0; int allocatedSlots = 0; - for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + for (int slot = 0; slot < getTotalSlotCountLocked(); ++slot) { bool isInFreeSlots = mFreeSlots.count(slot) != 0; bool isInFreeBuffers = std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) != diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 2e7cef0847..c241482827 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -40,6 +40,7 @@ #include <gui/TraceUtils.h> #include <private/gui/BufferQueueThreadState.h> +#include <utils/Errors.h> #include <utils/Log.h> #include <utils/Trace.h> @@ -108,9 +109,9 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_INIT; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + int maxSlot = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= maxSlot) { + BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, maxSlot); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("requestBuffer: slot %d is not owned by the producer " @@ -123,6 +124,49 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +status_t BufferQueueProducer::extendSlotCount(int size) { + ATRACE_CALL(); + + sp<IConsumerListener> listener; + { + std::lock_guard<std::mutex> lock(mCore->mMutex); + BQ_LOGV("extendSlotCount: size %d", size); + + if (mCore->mIsAbandoned) { + BQ_LOGE("extendSlotCount: BufferQueue has been abandoned"); + return NO_INIT; + } + + if (!mCore->mAllowExtendedSlotCount) { + BQ_LOGE("extendSlotCount: Consumer did not allow unlimited slots"); + return INVALID_OPERATION; + } + + int maxBeforeExtension = mCore->mMaxBufferCount; + + if (size == maxBeforeExtension) { + return NO_ERROR; + } + + if (size < maxBeforeExtension) { + return BAD_VALUE; + } + + if (status_t ret = mCore->extendSlotCountLocked(size); ret != OK) { + return ret; + } + listener = mCore->mConsumerListener; + } + + if (listener) { + listener->onSlotCountChanged(size); + } + + return NO_ERROR; +} +#endif + status_t BufferQueueProducer::setMaxDequeuedBufferCount( int maxDequeuedBuffers) { int maxBufferCount; @@ -170,9 +214,10 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers, int bufferCount = mCore->getMinUndequeuedBufferCountLocked(); bufferCount += maxDequeuedBuffers; - if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { + if (bufferCount > mCore->getTotalSlotCountLocked()) { BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large " - "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + "(max %d)", + bufferCount, mCore->getTotalSlotCountLocked()); return BAD_VALUE; } @@ -756,9 +801,9 @@ status_t BufferQueueProducer::detachBuffer(int slot) { return BAD_VALUE; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount) { + BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { // TODO(http://b/140581935): This message is BQ_LOGW because it @@ -993,9 +1038,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, return NO_INIT; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount) { + BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("queueBuffer: slot %d is not owned by the producer " @@ -1239,9 +1284,9 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { return BAD_VALUE; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, - BufferQueueDefs::NUM_BUFFER_SLOTS); + const int totalSlotCount = mCore->getTotalSlotCountLocked(); + if (slot < 0 || slot >= totalSlotCount) { + BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, totalSlotCount); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " @@ -1409,6 +1454,9 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; output->maxBufferCount = mCore->mMaxBufferCount; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + output->isSlotExpansionAllowed = mCore->mAllowExtendedSlotCount; +#endif if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 602bba8dab..504509dbec 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -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 { - mConsumer->setConsumerName(mName); + 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,11 +284,23 @@ void ConsumerBase::onBuffersReleased() { freeBufferLocked(i); } } +#endif } void ConsumerBase::onSidebandStreamChanged() { } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +void ConsumerBase::onSlotCountChanged(int slotCount) { + CB_LOGV("onSlotCountChanged: %d", slotCount); + Mutex::Autolock lock(mMutex); + + if (slotCount > (int)mSlots.size()) { + mSlots.resize(slotCount); + } +} +#endif + void ConsumerBase::abandon() { CB_LOGV("abandon"); Mutex::Autolock lock(mMutex); @@ -270,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 @@ -387,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) @@ -448,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++) { @@ -455,6 +524,8 @@ status_t ConsumerBase::discardFreeBuffers() { freeBufferLocked(i); } } +#endif + return OK; } @@ -596,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; } @@ -615,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 && diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index f2173cd740..168129b1f7 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -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,27 +132,29 @@ 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), - mCurrentCrop(Rect::EMPTY_RECT), - mCurrentTransform(0), - mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mCurrentFence(Fence::NO_FENCE), - mCurrentTimestamp(0), - mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), - mCurrentFrameNumber(0), - mDefaultWidth(1), - mDefaultHeight(1), - mFilteringEnabled(true), - mTexName(tex), - mUseFenceSync(useFenceSync), - mTexTarget(texTarget), - mEglDisplay(EGL_NO_DISPLAY), - mEglContext(EGL_NO_CONTEXT), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), - mAttached(true) -{ +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), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(tex), + mUseFenceSync(useFenceSync), + 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"); 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) { diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index f3bd90cffb..939db594ec 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -31,7 +31,8 @@ enum class Tag : uint32_t { ON_FRAME_DEQUEUED, ON_FRAME_CANCELLED, ON_FRAME_DETACHED, - LAST = ON_FRAME_DETACHED, + ON_SLOT_COUNT_CHANGED, + LAST = ON_SLOT_COUNT_CHANGED, }; } // Anonymous namespace @@ -85,6 +86,14 @@ public: FrameEventHistoryDelta* /*outDelta*/) override { LOG_ALWAYS_FATAL("IConsumerListener::addAndGetFrameTimestamps cannot be proxied"); } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + void onSlotCountChanged(int slotCount) override { + callRemoteAsync< + decltype(&IConsumerListener::onSlotCountChanged)>(Tag::ON_SLOT_COUNT_CHANGED, + slotCount); + } +#endif }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see @@ -116,6 +125,13 @@ status_t BnConsumerListener::onTransact(uint32_t code, const Parcel& data, Parce return callLocalAsync(data, reply, &IConsumerListener::onFrameCancelled); case Tag::ON_FRAME_DETACHED: return callLocalAsync(data, reply, &IConsumerListener::onFrameDetached); + case Tag::ON_SLOT_COUNT_CHANGED: { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + return callLocalAsync(data, reply, &IConsumerListener::onSlotCountChanged); +#else + return INVALID_OPERATION; +#endif + } } } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 282957b940..c1b65689d6 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -16,6 +16,7 @@ #include <gui/IGraphicBufferConsumer.h> +#include <com_android_graphics_libgui_flags.h> #include <gui/BufferItem.h> #include <gui/IConsumerListener.h> @@ -24,6 +25,7 @@ #include <ui/Fence.h> #include <ui/GraphicBuffer.h> +#include <utils/Errors.h> #include <utils/NativeHandle.h> #include <utils/String8.h> #include <cstdint> @@ -53,7 +55,9 @@ enum class Tag : uint32_t { GET_OCCUPANCY_HISTORY, DISCARD_FREE_BUFFERS, DUMP_STATE, - LAST = DUMP_STATE, + ALLOW_UNLIMITED_SLOTS, + GET_RELEASED_BUFFERS_EXTENDED, + LAST = GET_RELEASED_BUFFERS_EXTENDED, }; } // Anonymous namespace @@ -104,11 +108,25 @@ public: return callRemote<Signature>(Tag::GET_RELEASED_BUFFERS, slotMask); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + status_t getReleasedBuffersExtended(std::vector<bool>* slotMask) override { + using Signature = decltype(&IGraphicBufferConsumer::getReleasedBuffersExtended); + return callRemote<Signature>(Tag::GET_RELEASED_BUFFERS_EXTENDED, slotMask); + } +#endif + status_t setDefaultBufferSize(uint32_t width, uint32_t height) override { using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferSize); return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_SIZE, width, height); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + status_t allowUnlimitedSlots(bool allowUnlimitedSlots) override { + using Signature = decltype(&IGraphicBufferConsumer::allowUnlimitedSlots); + return callRemote<Signature>(Tag::ALLOW_UNLIMITED_SLOTS, allowUnlimitedSlots); + } +#endif + status_t setMaxBufferCount(int bufferCount) override { using Signature = decltype(&IGraphicBufferConsumer::setMaxBufferCount); return callRemote<Signature>(Tag::SET_MAX_BUFFER_COUNT, bufferCount); @@ -228,6 +246,20 @@ status_t BnGraphicBufferConsumer::onTransact(uint32_t code, const Parcel& data, using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const; return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState); } + case Tag::GET_RELEASED_BUFFERS_EXTENDED: { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + return callLocal(data, reply, &IGraphicBufferConsumer::getReleasedBuffersExtended); +#else + return INVALID_OPERATION; +#endif + } + case Tag::ALLOW_UNLIMITED_SLOTS: { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + return callLocal(data, reply, &IGraphicBufferConsumer::allowUnlimitedSlots); +#else + return INVALID_OPERATION; +#endif + } } } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 09144806ee..9f71eb16e7 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -81,6 +81,7 @@ enum { GET_LAST_QUEUED_BUFFER2, SET_FRAME_RATE, SET_ADDITIONAL_OPTIONS, + SET_MAX_BUFER_COUNT_EXTENDED, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -149,6 +150,20 @@ public: return result; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + status_t extendSlotCount(int size) override { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(size); + status_t result = remote()->transact(SET_MAX_BUFER_COUNT_EXTENDED, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } +#endif + virtual status_t setAsyncMode(bool async) { Parcel data, reply; data.writeInterfaceToken( @@ -981,6 +996,14 @@ IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, // ---------------------------------------------------------------------- +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +status_t IGraphicBufferProducer::extendSlotCount(int size) { + // No-op for IGBP other than BufferQueue. + (void)size; + return INVALID_OPERATION; +} +#endif + status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { // No-op for IGBP other than BufferQueue. (void) drop; @@ -1582,6 +1605,15 @@ status_t BnGraphicBufferProducer::onTransact( return NO_ERROR; } #endif +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + case SET_MAX_BUFER_COUNT_EXTENDED: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + int size = data.readInt32(); + status_t result = extendSlotCount(size); + reply->writeInt32(result); + return NO_ERROR; + } +#endif } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferProducerFlattenables.cpp b/libs/gui/IGraphicBufferProducerFlattenables.cpp index 4e92a39973..8b2e2ddc59 100644 --- a/libs/gui/IGraphicBufferProducerFlattenables.cpp +++ b/libs/gui/IGraphicBufferProducerFlattenables.cpp @@ -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) { diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e41f9bbf43..ec23365e1f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -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(); } } diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index 0948c4d076..f1c75d3a45 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -76,6 +76,9 @@ public: void onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; #endif +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + void onSlotCountChanged(int slotCount) override; +#endif private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index 6aa801ab86..e00c44eb70 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -96,11 +96,26 @@ public: // This should be called from the onBuffersReleased() callback. virtual status_t getReleasedBuffers(uint64_t* outSlotMask); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // getReleasedBuffers sets the values pointed to by outSlotMask to the bits + // indicating which buffer slots have been released by the BufferQueue + // but have not yet been released by the consumer. + // + // This should be called from the onBuffersReleased() callback when + // allowUnlimitedSlots has been called. + virtual status_t getReleasedBuffersExtended(std::vector<bool>* outSlotMask) override; +#endif + // setDefaultBufferSize is used to set the size of buffers returned by // dequeueBuffer when a width and height of zero is requested. Default // is 1x1. virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // see IGraphicBufferConsumer::allowUnlimitedSlots + virtual status_t allowUnlimitedSlots(bool allowUnlimitedSlots) override; +#endif + // see IGraphicBufferConsumer::setMaxBufferCount virtual status_t setMaxBufferCount(int bufferCount); diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 77cdf2c9f3..7f92a46053 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -32,10 +32,11 @@ #include <utils/Trace.h> #include <utils/Vector.h> +#include <condition_variable> #include <list> -#include <set> #include <mutex> -#include <condition_variable> +#include <set> +#include <vector> #define ATRACE_BUFFER_INDEX(index) \ do { \ @@ -91,6 +92,10 @@ private: // Dump our state in a string void dumpState(const String8& prefix, String8* outResult) const; + // getTotalSlotCountLocked returns the total number of slots in use by the + // buffer queue at this time. + int getTotalSlotCountLocked() const; + // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we're in asynchronous mode. @@ -120,6 +125,10 @@ private: int getMaxBufferCountLocked(bool asyncMode, bool dequeueBufferCannotBlock, int maxBufferCount) const; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // This resizes mSlots to the given size, but only if it's increasing. + status_t extendSlotCountLocked(int size); +#endif // clearBufferSlotLocked frees the GraphicBuffer and sync resources for the // given slot. void clearBufferSlotLocked(int slot); @@ -204,7 +213,7 @@ private: // mConnectedProducerListener will not trigger onBufferAttached() callback. bool mBufferAttachedCbEnabled; - // mSlots is an array of buffer slots that must be mirrored on the producer + // mSlots is a collection of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer // and consumer without sending a GraphicBuffer over Binder. The entire // array is initialized to NULL at construction time, and buffers are @@ -266,8 +275,14 @@ private: // is specified. android_dataspace mDefaultBufferDataSpace; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // mAllowExtendedSlotCount is set by the consumer to permit the producer to + // request an unlimited number of slots. + bool mAllowExtendedSlotCount; +#endif + // mMaxBufferCount is the limit on the number of buffers that will be - // allocated at one time. This limit can be set by the consumer. + // allocated at one time. int mMaxBufferCount; // mMaxAcquiredBufferCount is the number of buffers that the consumer may diff --git a/libs/gui/include/gui/BufferQueueDefs.h b/libs/gui/include/gui/BufferQueueDefs.h index ffafb49615..42cf439450 100644 --- a/libs/gui/include/gui/BufferQueueDefs.h +++ b/libs/gui/include/gui/BufferQueueDefs.h @@ -17,6 +17,7 @@ #ifndef ANDROID_GUI_BUFFERQUEUECOREDEFS_H #define ANDROID_GUI_BUFFERQUEUECOREDEFS_H +#include <com_android_graphics_libgui_flags.h> #include <gui/BufferSlot.h> #include <ui/BufferQueueDefs.h> @@ -24,7 +25,11 @@ namespace android { class BufferQueueCore; namespace BufferQueueDefs { - typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + typedef std::vector<BufferSlot> SlotsType; +#else + typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; +#endif } // namespace BufferQueueDefs } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 086ce7ce56..50abadb922 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -47,6 +47,11 @@ public: // flags indicating that previously-returned buffers are no longer valid. virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // see IGraphicsBufferProducer::extendSlotCount + virtual status_t extendSlotCount(int size) override; +#endif + // see IGraphicsBufferProducer::setMaxDequeuedBufferCount virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index e976aa48be..5cd19c1583 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -185,7 +185,9 @@ protected: virtual void onFrameDetached(const uint64_t bufferId) override; virtual void onBuffersReleased() override; virtual void onSidebandStreamChanged() override; - +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + virtual void onSlotCountChanged(int slotCount) override; +#endif virtual int getSlotForBufferLocked(const sp<GraphicBuffer>& buffer); virtual status_t detachBufferLocked(int slotIndex); @@ -284,7 +286,11 @@ protected: // 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<Slot> mSlots; +#else Slot mSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; +#endif // mAbandoned indicates that the BufferQueue will no longer be used to // consume images buffers pushed to it using the IGraphicBufferProducer diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 8a66dc0cf1..30cbfa2f9f 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -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, diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index 51d3959de7..1695aae876 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -98,6 +98,16 @@ public: virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) {} #endif + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // Notifies the consumer that IGraphicBufferProducer::extendSlotCount has + // been called and the total slot count has increased. + // + // This will only ever be called if + // IGraphicBufferConsumer::allowUnlimitedSlots has been called on the + // consumer. + virtual void onSlotCountChanged(int /* slotCount */) {} +#endif }; #ifndef NO_BINDER diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 18f5488173..56eb291335 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -16,6 +16,7 @@ #pragma once +#include <com_android_graphics_libgui_flags.h> #include <gui/OccupancyTracker.h> #include <binder/IInterface.h> @@ -35,6 +36,10 @@ class Fence; class GraphicBuffer; class IConsumerListener; class NativeHandle; + +/* + * See IGraphicBufferProducer for details on SLOT_COUNT. + */ #ifndef NO_BINDER class IGraphicBufferConsumer : public IInterface { public: @@ -92,7 +97,7 @@ public: // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - the given slot number is invalid, either because it is out of the range - // [0, NUM_BUFFER_SLOTS) or because the slot it refers to is not + // [0, SLOT_COUNT) or because the slot it refers to is not // currently acquired. virtual status_t detachBuffer(int slot) = 0; @@ -173,6 +178,19 @@ public: // * NO_INIT - the BufferQueue has been abandoned. virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // getReleasedBuffersExtended for each slot, sets slotMask[slot] to 1 if it + // corresponds to a released buffer slot. In particular, a released buffer + // is one that has been released by the BufferQueue but has not yet been + // released by the consumer. + // + // This should be called from the onBuffersReleased() callback. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the BufferQueue has been abandoned. + virtual status_t getReleasedBuffersExtended(std::vector<bool>* slotMask) = 0; +#endif + // setDefaultBufferSize is used to set the size of buffers returned by dequeueBuffer when a // width and height of zero is requested. Default is 1x1. // @@ -180,6 +198,26 @@ public: // * BAD_VALUE - either w or h was zero virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // allowUnlimitedSlots allows the producer to set the upper bound on slots. + // + // Must be called before the producer is connected. If the producer + // increases the slot count, an IConsumerListener::onSlotCountChanged + // update is sent. + // + // This can not be used with setMaxBufferCount. Calls after + // setMaxBufferCount will fail and calls to setMaxBufferCount after setting + // this to true will fail. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the BufferQueue has been abandoned + // * INVALID_OPERATION - one of the following errors has occurred: + // * Producer has been connected + // * setMaxBufferCount has been called and shrunk the + // BufferQueue. + virtual status_t allowUnlimitedSlots(bool allowUnlimitedSlots) = 0; +#endif + // setMaxBufferCount sets the maximum value for the number of buffers used in the BufferQueue // (the initial default is NUM_BUFFER_SLOTS). If a call to setMaxAcquiredBufferCount (by the // consumer), or a call to setAsyncMode or setMaxDequeuedBufferCount (by the producer), would diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index a42ddc466c..7accca6298 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -72,6 +72,14 @@ using HGraphicBufferProducerV2_0 = * dequeueBuffer() to get an empty buffer, fills it with data, then * calls queueBuffer() to make it available to the consumer. * + * BufferQueues have a size, which we'll refer to in other comments as + * SLOT_COUNT. Its default is 64 (NUM_BUFFER_SLOTS). It can be adjusted by + * the IGraphicBufferConsumer::setMaxBufferCount, or when + * IGraphicBufferConsumer::allowUnlimitedSlots is set to true, by + * IGraphicBufferProducer::extendSlotCount. The actual number of buffers in use + * is a function of various configurations, including whether we're in single + * buffer mode, the maximum dequeuable/aquirable buffers, and SLOT_COUNT. + * * This class was previously called ISurfaceTexture. */ #ifndef NO_BINDER @@ -106,7 +114,7 @@ public: // slot->buffer mapping so that it's not necessary to transfer a // GraphicBuffer for every dequeue operation. // - // The slot must be in the range of [0, NUM_BUFFER_SLOTS). + // The slot must be in the range of [0, SLOT_COUNT). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not @@ -116,6 +124,30 @@ public: // * buffer specified by the slot is not dequeued virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + // extendSlotCount sets the maximum slot count (SLOT_COUNT) to the given + // size. This feature must be enabled by the consumer to function via + // IGraphicBufferConsumer::allowUnlimitedSlots. This must be called before + // the producer connects. + // + // After calling this, any slot can be returned in the [0, size) range. + // Callers are responsible for the allocation of the appropriate slots + // array for their own buffer cache. + // + // On success, the consumer is notified (so that it can increase its own + // slot cache). + // + // Return of a value other than NO_ERROR means that an error has occurred: + // * NO_INIT - the buffer queue has been abandoned + // * INVALID_OPERATION - one of the following conditions has occurred: + // * The producer is connected already + // * The consumer didn't call allowUnlimitedSlots + // * BAD_VALUE - The value is smaller than the previous max size + // (initialized to 64, then whatever the last call to this + // was) + virtual status_t extendSlotCount(int size); +#endif + // setMaxDequeuedBufferCount sets the maximum number of buffers that can be // dequeued by the producer at one time. If this method succeeds, any new // buffer slots will be both unallocated and owned by the BufferQueue object @@ -129,7 +161,7 @@ public: // will result in a BAD_VALUE error. // // The buffer count should be at least 1 (inclusive), but at most - // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The + // (SLOT_COUNT - the minimum undequeued buffer count) (exclusive). The // minimum undequeued buffer count can be obtained by calling // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS). // @@ -239,8 +271,8 @@ public: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - the given slot number is invalid, either because it is - // out of the range [0, NUM_BUFFER_SLOTS), or because the slot - // it refers to is not currently dequeued and requested. + // out of the range [0, SLOT_COUNT), or because the slot it + // refers to is not currently dequeued and requested. virtual status_t detachBuffer(int slot) = 0; // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, @@ -415,6 +447,7 @@ public: FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; int maxBufferCount{BufferQueueDefs::NUM_BUFFER_SLOTS}; + bool isSlotExpansionAllowed{false}; status_t result{NO_ERROR}; }; @@ -430,7 +463,7 @@ public: // below). Any other properties (zero point, etc) // are client-dependent, and should be documented by the client. // - // The slot must be in the range of [0, NUM_BUFFER_SLOTS). + // The slot must be in the range of [0, SLOT_COUNT). // // Upon success, the output will be filled with meaningful values // (refer to the documentation below). @@ -460,7 +493,7 @@ public: // // The buffer is not queued for use by the consumer. // - // The slot must be in the range of [0, NUM_BUFFER_SLOTS). + // The slot must be in the range of [0, SLOT_COUNT). // // The buffer will not be overwritten until the fence signals. The fence // will usually be the one obtained from dequeueBuffer. diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 14a351316d..755674d9e6 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -558,7 +558,11 @@ protected: // 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<BufferSlot> mSlots; +#else BufferSlot mSlots[NUM_BUFFER_SLOTS]; +#endif // mReqWidth is the buffer width that will be requested at the next dequeue // operation. It is initialized to 1. @@ -732,6 +736,10 @@ protected: std::vector<sp<GraphicBuffer>> mRemovedBuffers; int mMaxBufferCount; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + bool mIsSlotExpansionAllowed; +#endif + sp<IProducerListener> mListenerProxy; // Get and flush the buffers of given slots, if the buffer in the slot diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index f07747f32f..87051a7aac 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -55,6 +55,7 @@ cc_test { "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_EXTENDEDALLOCATE=true", "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_CONSUMER_BASE_OWNS_BQ=true", "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_PLATFORM_API_IMPROVEMENTS=true", + "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_UNLIMITED_SLOTS=true", ], srcs: [ diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index 3b6a66efe9..6453885804 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -22,8 +22,11 @@ #include <gui/BufferItemConsumer.h> #include <gui/IProducerListener.h> #include <gui/Surface.h> +#include <ui/BufferQueueDefs.h> #include <ui/GraphicBuffer.h> +#include <unordered_set> + namespace android { static constexpr int kWidth = 100; @@ -57,6 +60,8 @@ class BufferItemConsumerTest : public ::testing::Test { }; void SetUp() override { + mBuffers.resize(BufferQueueDefs::NUM_BUFFER_SLOTS); + mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true); String8 name("BufferItemConsumer_Under_Test"); mBIC->setName(name); @@ -137,6 +142,11 @@ class BufferItemConsumerTest : public ::testing::Test { ASSERT_EQ(NO_ERROR, ret); } + void DetachBuffer(int slot) { + ALOGD("detachBuffer: slot=%d", slot); + status_t ret = mBIC->detachBuffer(mBuffers[slot]); + ASSERT_EQ(NO_ERROR, ret); + } std::mutex mMutex; int mFreedBufferCount{0}; @@ -146,7 +156,7 @@ class BufferItemConsumerTest : public ::testing::Test { sp<BufferFreedListener> mBFL; sp<IGraphicBufferProducer> mProducer; sp<IGraphicBufferConsumer> mConsumer; - sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; + std::vector<sp<GraphicBuffer>> mBuffers; }; // Test that detaching buffer from consumer side triggers onBufferFreed. @@ -239,4 +249,52 @@ TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) { } #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +TEST_F(BufferItemConsumerTest, UnlimitedSlots_AcquireReleaseAll) { + ASSERT_EQ(OK, mProducer->extendSlotCount(256)); + mBuffers.resize(256); + + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(100)); + + std::unordered_set<int> slots; + for (int i = 0; i < 100; i++) { + int slot; + DequeueBuffer(&slot); + slots.insert(slot); + } + EXPECT_EQ(100u, slots.size()); + + for (int dequeuedSlot : slots) { + QueueBuffer(dequeuedSlot); + + int slot; + AcquireBuffer(&slot); + ReleaseBuffer(slot); + } +} + +TEST_F(BufferItemConsumerTest, UnlimitedSlots_AcquireDetachAll) { + ASSERT_EQ(OK, mProducer->extendSlotCount(256)); + mBuffers.resize(256); + + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(100)); + + std::unordered_set<int> slots; + for (int i = 0; i < 100; i++) { + int slot; + DequeueBuffer(&slot); + slots.insert(slot); + } + EXPECT_EQ(100u, slots.size()); + + for (int dequeuedSlot : slots) { + QueueBuffer(dequeuedSlot); + + int slot; + AcquireBuffer(&slot); + DetachBuffer(slot); + } +} +#endif + } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 16060990bd..77b4ae8623 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -20,6 +20,8 @@ #include "Constants.h" #include "MockConsumer.h" +#include <EGL/egl.h> + #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferQueue.h> @@ -44,7 +46,9 @@ #include <gtest/gtest.h> #include <future> +#include <optional> #include <thread> +#include <unordered_map> #include <com_android_graphics_libgui_flags.h> @@ -1612,4 +1616,221 @@ TEST_F(BufferQueueTest, PassesThroughPictureProfileHandle) { } } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +struct MockUnlimitedSlotConsumer : public MockConsumer { + virtual void onSlotCountChanged(int size) override { mSize = size; } + + std::optional<int> mSize; +}; + +TEST_F(BufferQueueTest, UnlimitedSlots_FailsWhenNotAllowed) { + createBufferQueue(); + + sp<MockUnlimitedSlotConsumer> mc = sp<MockUnlimitedSlotConsumer>::make(); + EXPECT_EQ(OK, mConsumer->consumerConnect(mc, false)); + + EXPECT_EQ(INVALID_OPERATION, mProducer->extendSlotCount(64)); + EXPECT_EQ(INVALID_OPERATION, mProducer->extendSlotCount(32)); + EXPECT_EQ(INVALID_OPERATION, mProducer->extendSlotCount(128)); + + EXPECT_EQ(std::nullopt, mc->mSize); +} + +TEST_F(BufferQueueTest, UnlimitedSlots_OnlyAllowedForExtensions) { + createBufferQueue(); + + sp<MockUnlimitedSlotConsumer> consumerListener = sp<MockUnlimitedSlotConsumer>::make(); + EXPECT_EQ(OK, mConsumer->consumerConnect(consumerListener, false)); + EXPECT_EQ(OK, mConsumer->allowUnlimitedSlots(true)); + + EXPECT_EQ(BAD_VALUE, mProducer->extendSlotCount(32)); + EXPECT_EQ(OK, mProducer->extendSlotCount(64)); + EXPECT_EQ(OK, mProducer->extendSlotCount(128)); + EXPECT_EQ(128, *consumerListener->mSize); + + EXPECT_EQ(OK, mProducer->extendSlotCount(128)); + EXPECT_EQ(BAD_VALUE, mProducer->extendSlotCount(127)); +} + +class BufferQueueUnlimitedTest : public BufferQueueTest { +protected: + static constexpr auto kMaxBufferCount = 128; + static constexpr auto kAcquirableBufferCount = 2; + static constexpr auto kDequeableBufferCount = kMaxBufferCount - kAcquirableBufferCount; + + virtual void SetUp() override { + BufferQueueTest::SetUp(); + + createBufferQueue(); + setUpConsumer(); + setUpProducer(); + } + + void setUpConsumer() { + EXPECT_EQ(OK, mConsumer->consumerConnect(mConsumerListener, false)); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + EXPECT_EQ(OK, mConsumer->allowUnlimitedSlots(true)); +#endif + EXPECT_EQ(OK, mConsumer->setConsumerUsageBits(GraphicBuffer::USAGE_SW_READ_OFTEN)); + EXPECT_EQ(OK, mConsumer->setDefaultBufferSize(10, 10)); + EXPECT_EQ(OK, mConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888)); + EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(kAcquirableBufferCount)); + } + + void setUpProducer() { + EXPECT_EQ(OK, mProducer->extendSlotCount(kMaxBufferCount)); + + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(OK, + mProducer->connect(mProducerListener, NATIVE_WINDOW_API_CPU, + /*producerControlledByApp*/ true, &output)); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + ASSERT_TRUE(output.isSlotExpansionAllowed); +#endif + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(kDequeableBufferCount)); + ASSERT_EQ(OK, mProducer->allowAllocation(true)); + } + + std::unordered_map<int, sp<Fence>> dequeueAll() { + std::unordered_map<int, sp<Fence>> slotsToFences; + + for (int i = 0; i < kDequeableBufferCount; ++i) { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + + status_t ret = + mProducer->dequeueBuffer(&slot, &fence, /*w*/ 0, /*h*/ 0, /*format*/ 0, + /*uint64_t*/ 0, + /*outBufferAge*/ nullptr, /*outTimestamps*/ nullptr); + if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { + EXPECT_EQ(OK, mProducer->requestBuffer(slot, &buffer)) + << "Unable to request buffer for slot " << slot; + } + EXPECT_FALSE(slotsToFences.contains(slot)); + slotsToFences.emplace(slot, fence); + } + EXPECT_EQ(kDequeableBufferCount, (int)slotsToFences.size()); + return slotsToFences; + } + + sp<MockUnlimitedSlotConsumer> mConsumerListener = sp<MockUnlimitedSlotConsumer>::make(); + sp<StubProducerListener> mProducerListener = sp<StubProducerListener>::make(); +}; + +TEST_F(BufferQueueUnlimitedTest, ExpandOverridesConsumerMaxBuffers) { + createBufferQueue(); + setUpConsumer(); + EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10)); + + setUpProducer(); + + EXPECT_EQ(kDequeableBufferCount, (int)dequeueAll().size()); +} + +TEST_F(BufferQueueUnlimitedTest, CanDetachAll) { + auto slotsToFences = dequeueAll(); + for (auto& [slot, fence] : slotsToFences) { + EXPECT_EQ(OK, mProducer->detachBuffer(slot)); + } +} + +TEST_F(BufferQueueUnlimitedTest, CanCancelAll) { + auto slotsToFences = dequeueAll(); + for (auto& [slot, fence] : slotsToFences) { + EXPECT_EQ(OK, mProducer->cancelBuffer(slot, fence)); + } +} + +TEST_F(BufferQueueUnlimitedTest, CanAcquireAndReleaseAll) { + auto slotsToFences = dequeueAll(); + for (auto& [slot, fence] : slotsToFences) { + IGraphicBufferProducer::QueueBufferInput input; + input.fence = fence; + + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); + + BufferItem buffer; + EXPECT_EQ(OK, mConsumer->acquireBuffer(&buffer, 0)); + EXPECT_EQ(OK, + mConsumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber, EGL_NO_DISPLAY, + EGL_NO_SYNC, buffer.mFence)); + } +} + +TEST_F(BufferQueueUnlimitedTest, CanAcquireAndDetachAll) { + auto slotsToFences = dequeueAll(); + for (auto& [slot, fence] : slotsToFences) { + IGraphicBufferProducer::QueueBufferInput input; + input.fence = fence; + + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); + + BufferItem buffer; + EXPECT_EQ(OK, mConsumer->acquireBuffer(&buffer, 0)); + EXPECT_EQ(OK, mConsumer->detachBuffer(buffer.mSlot)); + } +} + +TEST_F(BufferQueueUnlimitedTest, GetReleasedBuffersExtended) { + // First, acquire and release all the buffers so the consumer "knows" about + // them + auto slotsToFences = dequeueAll(); + + std::vector<bool> releasedSlots; + EXPECT_EQ(OK, mConsumer->getReleasedBuffersExtended(&releasedSlots)); + for (auto& [slot, _] : slotsToFences) { + EXPECT_TRUE(releasedSlots[slot]) + << "Slots that haven't been acquired will show up as released."; + } + for (auto& [slot, fence] : slotsToFences) { + IGraphicBufferProducer::QueueBufferInput input; + input.fence = fence; + + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); + + BufferItem buffer; + EXPECT_EQ(OK, mConsumer->acquireBuffer(&buffer, 0)); + EXPECT_EQ(OK, + mConsumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR, buffer.mFence)); + } + + EXPECT_EQ(OK, mConsumer->getReleasedBuffersExtended(&releasedSlots)); + for (auto& [slot, _] : slotsToFences) { + EXPECT_FALSE(releasedSlots[slot]) + << "Slots that have been acquired will show up as not released."; + } + + // Then, alternatively cancel and detach (release) buffers. Only detached + // buffers should be returned by getReleasedBuffersExtended + slotsToFences = dequeueAll(); + std::set<int> cancelledSlots; + std::set<int> detachedSlots; + bool cancel; + for (auto& [slot, fence] : slotsToFences) { + if (cancel) { + EXPECT_EQ(OK, mProducer->cancelBuffer(slot, fence)); + cancelledSlots.insert(slot); + } else { + EXPECT_EQ(OK, mProducer->detachBuffer(slot)); + detachedSlots.insert(slot); + } + cancel = !cancel; + } + + EXPECT_EQ(OK, mConsumer->getReleasedBuffersExtended(&releasedSlots)); + for (int slot : detachedSlots) { + EXPECT_TRUE(releasedSlots[slot]) << "Slots that are detached are released."; + } + for (int slot : cancelledSlots) { + EXPECT_FALSE(releasedSlots[slot]) + << "Slots that are still held in the queue are not released."; + } +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) } // namespace android diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index f4239cb69e..9476930de3 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -803,6 +803,27 @@ INSTANTIATE_TEST_CASE_P(Rgba8888Tests, ::testing::ValuesIn(rgba8888TestSets)); #endif - - +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +TEST(CpuConsumerSlotTest, UnlimitedSlots_AcquireReleaseAll) { + sp<CpuConsumer> cpuConsumer = sp<CpuConsumer>::make(3); + sp<Surface> surface = cpuConsumer->getSurface(); + sp<SurfaceListener> listener = sp<StubSurfaceListener>::make(); + + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(256)); + + std::vector<Surface::BatchBuffer> buffers(256); + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + + for (auto& buffer : buffers) { + sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(buffer.buffer); + sp<Fence> fence = sp<Fence>::make(buffer.fenceFd); + EXPECT_EQ(OK, surface->queueBuffer(graphicBuffer, fence)); + + CpuConsumer::LockedBuffer nativeBuffer; + EXPECT_EQ(OK, cpuConsumer->lockNextBuffer(&nativeBuffer)); + EXPECT_EQ(OK, cpuConsumer->unlockBuffer(nativeBuffer)); + } +} +#endif } // namespace android diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp index b60995a624..11383d906b 100644 --- a/libs/gui/tests/FillBuffer.cpp +++ b/libs/gui/tests/FillBuffer.cpp @@ -76,7 +76,7 @@ void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, } void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { - const size_t PIXEL_SIZE = 4; + constexpr size_t PIXEL_SIZE = 4; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { off_t offset = (y * stride + x) * PIXEL_SIZE; @@ -89,6 +89,21 @@ void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { } } +void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride, uint8_t r, uint8_t g, uint8_t b, + uint8_t a) { + constexpr size_t PIXEL_SIZE = 4; + + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + off_t offset = (y * stride + x) * PIXEL_SIZE; + buf[offset] = r; + buf[offset + 1] = g; + buf[offset + 2] = b; + buf[offset + 3] = a; + } + } +} + void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) { android_native_buffer_t* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), diff --git a/libs/gui/tests/FillBuffer.h b/libs/gui/tests/FillBuffer.h index b584179318..f5d6b8bbda 100644 --- a/libs/gui/tests/FillBuffer.h +++ b/libs/gui/tests/FillBuffer.h @@ -30,6 +30,8 @@ void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, const android_native_rect_t& rect); void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride); +void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride, uint8_t r, uint8_t g, uint8_t b, + uint8_t a); // Produce a single RGBA8 frame by filling a buffer with a checkerboard pattern // using the CPU. This assumes that the ANativeWindow is already configured to diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index 449533aa57..b22b85332c 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "SurfaceTextureGL_test" //#define LOG_NDEBUG 0 +#include <gmock/gmock.h> + #include "SurfaceTextureGL.h" #include "DisconnectWaiter.h" @@ -735,4 +737,30 @@ TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { ASSERT_NE(NO_ERROR, mST->updateTexImage()); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +TEST_F(SurfaceTextureGLTest, TestUnlimitedSlots) { + ASSERT_EQ(OK, mSTC->connect(NATIVE_WINDOW_API_CPU, sp<StubSurfaceListener>::make())); + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(256)); + + std::vector<Surface::BatchBuffer> buffers(256); + ASSERT_EQ(OK, mSTC->dequeueBuffers(&buffers)); + ASSERT_EQ(256u, buffers.size()); + ASSERT_THAT(buffers, Each(Field(&Surface::BatchBuffer::buffer, ::testing::NotNull()))); + + for (size_t i = 0; i < buffers.size(); ++i) { + sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(buffers[i].buffer); + sp<Fence> fence = sp<Fence>::make(buffers[i].fenceFd); + + void* buf; + ASSERT_EQ(OK, graphicBuffer->lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, &buf)); + fillRGBA8Buffer((uint8_t*)buf, graphicBuffer->getWidth(), graphicBuffer->getHeight(), + graphicBuffer->getStride(), i, i, i, i); + graphicBuffer->unlock(); + + ASSERT_EQ(OK, mSTC->queueBuffer(graphicBuffer, fence)); + ASSERT_EQ(OK, mST->updateTexImage()); + checkPixel(0, 0, i, i, i, i); + } +} +#endif } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3185778acf..646e30e5a8 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -#include "gui/view/Surface.h" -#include "Constants.h" -#include "MockConsumer.h" - #include <gtest/gtest.h> #include <SurfaceFlingerProperties.h> @@ -36,10 +32,13 @@ #include <gui/IConsumerListener.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <gui/SyncScreenCaptureListener.h> +#include <gui/view/Surface.h> +#include <nativebase/nativebase.h> #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> #include <sys/types.h> @@ -47,6 +46,7 @@ #include <ui/BufferQueueDefs.h> #include <ui/DisplayMode.h> #include <ui/GraphicBuffer.h> +#include <ui/PixelFormat.h> #include <ui/Rect.h> #include <utils/Errors.h> #include <utils/String8.h> @@ -55,9 +55,12 @@ #include <cstddef> #include <cstdint> #include <future> +#include <iterator> #include <limits> #include <thread> +#include "Constants.h" +#include "MockConsumer.h" #include "testserver/TestServerClient.h" namespace android { @@ -2533,4 +2536,128 @@ TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements_Plural) { } #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) +TEST_F(SurfaceTest, UnlimitedSlots_FailsOnIncompatibleConsumer) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<IConsumerListener> consumerListener = sp<FakeConsumer>::make(); + + EXPECT_EQ(OK, consumer->allowUnlimitedSlots(false)); + EXPECT_EQ(OK, consumer->consumerConnect(consumerListener, /* consumerListener */ true)); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener)); + + EXPECT_NE(OK, surface->setMaxDequeuedBufferCount(128)) + << "We shouldn't be able to set high max buffer counts if the consumer doesn't allow " + "it"; +} + +TEST_F(SurfaceTest, UnlimitedSlots_CanDequeueAndQueueMoreThanOldMaximum) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<IConsumerListener> consumerListener = sp<FakeConsumer>::make(); + + EXPECT_EQ(OK, consumer->allowUnlimitedSlots(true)); + EXPECT_EQ(OK, consumer->consumerConnect(consumerListener, /* consumerListener */ true)); + EXPECT_EQ(OK, consumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888)); + EXPECT_EQ(OK, consumer->setConsumerUsageBits(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener)); + + EXPECT_EQ(OK, surface->setMaxDequeuedBufferCount(128)) + << "If unlimited slots are allowed, we should be able increase the max dequeued buffer " + "count arbitrarily"; + + std::vector<std::tuple<sp<GraphicBuffer>, sp<Fence>, int>> buffers; + for (int i = 0; i < 128; i++) { + sp<GraphicBuffer> buffer; + sp<Fence> fence; + ASSERT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)) << "Unable to dequeue buffer #" << i; + buffers.push_back({buffer, fence, i}); + } + + for (auto& [buffer, fence, idx] : buffers) { + ASSERT_EQ(OK, surface->queueBuffer(buffer, fence)) << "Unable to queue buffer #" << idx; + } +} + +TEST_F(SurfaceTest, UnlimitedSlots_CanDequeueAndDetachMoreThanOldMaximum) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<IConsumerListener> consumerListener = sp<FakeConsumer>::make(); + + EXPECT_EQ(OK, consumer->allowUnlimitedSlots(true)); + EXPECT_EQ(OK, consumer->consumerConnect(consumerListener, /* consumerListener */ true)); + EXPECT_EQ(OK, consumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888)); + EXPECT_EQ(OK, consumer->setConsumerUsageBits(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener)); + + EXPECT_EQ(OK, surface->setMaxDequeuedBufferCount(128)) + << "If unlimited slots are allowed, we should be able increase the max dequeued buffer " + "count arbitrarily"; + + std::vector<std::tuple<sp<GraphicBuffer>, sp<Fence>, int>> buffers; + for (int i = 0; i < 128; i++) { + sp<GraphicBuffer> buffer; + sp<Fence> fence; + ASSERT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)) << "Unable to dequeue buffer #" << i; + buffers.push_back({buffer, fence, i}); + } + + for (auto& [buffer, _, idx] : buffers) { + ASSERT_EQ(OK, surface->detachBuffer(buffer)) << "Unable to detach buffer #" << idx; + } +} + +TEST_F(SurfaceTest, UnlimitedSlots_BatchOperations) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<IConsumerListener> consumerListener = sp<FakeConsumer>::make(); + + EXPECT_EQ(OK, consumer->allowUnlimitedSlots(true)); + EXPECT_EQ(OK, consumer->consumerConnect(consumerListener, /* consumerListener */ true)); + EXPECT_EQ(OK, consumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888)); + EXPECT_EQ(OK, consumer->setConsumerUsageBits(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener)); + + EXPECT_EQ(OK, surface->setMaxDequeuedBufferCount(128)) + << "If unlimited slots are allowed, we should be able increase the max dequeued buffer " + "count arbitrarily"; + + std::vector<Surface::BatchBuffer> buffers(128); + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + EXPECT_EQ(128u, buffers.size()); + + std::vector<Surface::BatchQueuedBuffer> queuedBuffers; + std::transform(buffers.begin(), buffers.end(), std::back_inserter(queuedBuffers), + [](Surface::BatchBuffer& buffer) { + Surface::BatchQueuedBuffer out; + out.buffer = buffer.buffer; + out.fenceFd = buffer.fenceFd; + return out; + }); + + std::vector<SurfaceQueueBufferOutput> outputs; + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(128u, outputs.size()); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) } // namespace android |