From 2e614a493cbfbc34430993ee158378fba235a3b2 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Wed, 2 Oct 2024 19:31:53 +0000 Subject: libgui: Add support for unlimited slot BufferQueues BufferQueues can now be of unlimited size, according to the wishes of the producer. We add four new methods: - IGBC::allowUnlimitedSlots, which permits the IGBP to call extendSlotCount - IGBP::extendSlotCount, which increases the total available slot count to a fixed number and notifies the consumer via ICL::onSlotCountChanged - ICL::onSlotCountChanged, which notifies the consumer to resize its personal slot vector - IGBC::getReleasedBuffersExtented, which is like getReleasedBuffers but with an arbitrary sized bitvector instead of a fixed 64 bit vector The internal representation of the slots in BufferQueueCore is now a vector instead of an array, and can grow (but not shrink). The only consumers of these new APIs are intented to be Surface and ConsumerBase. Everything else is being migrated away from IGBP/IGBC anyway. This is part of go/warren-buffers. Bug: 341359814 Flag: com.android.graphics.libgui.flags.wb_unlimited_slots Test: new tests, old tests Change-Id: I0df872b9d6f9273854cc07a88d29b65451e1832a --- libs/gui/ConsumerBase.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'libs/gui/ConsumerBase.cpp') diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 602bba8dab..e772f44a4f 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -254,6 +254,17 @@ void ConsumerBase::onBuffersReleased() { 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); -- cgit v1.2.3-59-g8ed1b From 4f9c275b3f43c4f683b4778b3d3c5464d3dad9a0 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Tue, 22 Oct 2024 20:29:12 +0000 Subject: 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 --- libs/gui/ConsumerBase.cpp | 79 ++++++++++++-- libs/gui/GLConsumer.cpp | 64 +++++++---- libs/gui/IGraphicBufferProducerFlattenables.cpp | 4 +- libs/gui/Surface.cpp | 76 ++++++++++++- libs/gui/include/gui/GLConsumer.h | 8 +- libs/gui/include/gui/Surface.h | 8 ++ libs/gui/tests/BufferItemConsumer_test.cpp | 60 ++++++++++- libs/gui/tests/BufferQueue_test.cpp | 6 +- libs/gui/tests/CpuConsumer_test.cpp | 25 ++++- libs/gui/tests/FillBuffer.cpp | 17 ++- libs/gui/tests/FillBuffer.h | 2 + libs/gui/tests/SurfaceTextureGL_test.cpp | 28 +++++ libs/gui/tests/Surface_test.cpp | 135 +++++++++++++++++++++++- 13 files changed, 469 insertions(+), 43 deletions(-) (limited to 'libs/gui/ConsumerBase.cpp') diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index e772f44a4f..504509dbec 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -37,6 +37,8 @@ #include +#include + #include #include #include @@ -59,7 +61,11 @@ static int32_t createProcessUniqueId() { return android_atomic_inc(&globalCounter); } -ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : +ConsumerBase::ConsumerBase(const sp& 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& 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 producer; BufferQueue::createBufferQueue(&producer, &mConsumer, consumerIsSurfaceFlinger); mSurface = sp::make(producer, controlledByApp); @@ -77,7 +88,11 @@ ConsumerBase::ConsumerBase(bool controlledByApp, bool consumerIsSurfaceFlinger) ConsumerBase::ConsumerBase(const sp& producer, const sp& 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::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& 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 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 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) { +#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& 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& 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& 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, EGLDisplay display, EGLSyncKHR eglFence) { 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 #include +#include #include #include #include @@ -98,7 +99,10 @@ Surface::Surface(const sp& 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& 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* 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& 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* 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& slots, std::vector>* 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 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 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/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 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> mRemovedBuffers; int mMaxBufferCount; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + bool mIsSlotExpansionAllowed; +#endif + sp mListenerProxy; // Get and flush the buffers of given slots, if the buffer in the slot 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 #include #include +#include #include +#include + 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 mBFL; sp mProducer; sp mConsumer; - sp mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; + std::vector> 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 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 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 6138306dbe..77b4ae8623 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1669,7 +1669,9 @@ protected: 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)); @@ -1683,7 +1685,9 @@ protected: 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)); } 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 = sp::make(3); + sp surface = cpuConsumer->getSurface(); + sp listener = sp::make(); + + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(256)); + + std::vector buffers(256); + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + + for (auto& buffer : buffers) { + sp graphicBuffer = GraphicBuffer::from(buffer.buffer); + sp fence = sp::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& 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 + #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::make())); + ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(256)); + + std::vector 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::from(buffers[i].buffer); + sp fence = sp::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 76362ff272..e771d6db7f 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 #include @@ -36,10 +32,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -55,9 +55,12 @@ #include #include #include +#include #include #include +#include "Constants.h" +#include "MockConsumer.h" #include "testserver/TestServerClient.h" namespace android { @@ -2529,4 +2532,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 producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp consumerListener = sp::make(); + + EXPECT_EQ(OK, consumer->allowUnlimitedSlots(false)); + EXPECT_EQ(OK, consumer->consumerConnect(consumerListener, /* consumerListener */ true)); + + sp surface = sp::make(producer); + sp surfaceListener = sp::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 producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp consumerListener = sp::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 = sp::make(producer); + sp surfaceListener = sp::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, sp, int>> buffers; + for (int i = 0; i < 128; i++) { + sp buffer; + sp 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 producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp consumerListener = sp::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 = sp::make(producer); + sp surfaceListener = sp::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, sp, int>> buffers; + for (int i = 0; i < 128; i++) { + sp buffer; + sp 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 producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp consumerListener = sp::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 = sp::make(producer); + sp surfaceListener = sp::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 buffers(128); + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + EXPECT_EQ(128u, buffers.size()); + + std::vector 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 outputs; + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(128u, outputs.size()); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) } // namespace android -- cgit v1.2.3-59-g8ed1b