diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-12-13 02:05:43 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-12-13 02:05:43 +0000 |
commit | b4cb9e9297cc69dfaedf7d7d1458dcebe369d649 (patch) | |
tree | 4fbfde8b8bf725408635a9b48e1addf14f17aa4a | |
parent | fd4775b5c3a7c7beb800813e81667c6743ead65d (diff) | |
parent | 86ced3ef2e7f50c200ad483009eb2a214029f012 (diff) | |
download | native-b4cb9e9297cc69dfaedf7d7d1458dcebe369d649.tar.gz |
Snap for 6069307 from 86ced3ef2e7f50c200ad483009eb2a214029f012 to qt-qpr2-release
Change-Id: I26fb844d1e7c752fc67942392201e431054f20f6
-rw-r--r-- | libs/gui/BufferQueueConsumer.cpp | 10 | ||||
-rw-r--r-- | libs/gui/BufferQueueCore.cpp | 7 | ||||
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 5 | ||||
-rw-r--r-- | libs/gui/IProducerListener.cpp | 26 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 49 | ||||
-rw-r--r-- | libs/gui/include/gui/BufferQueueCore.h | 6 | ||||
-rw-r--r-- | libs/gui/include/gui/IProducerListener.h | 6 | ||||
-rw-r--r-- | libs/gui/include/gui/Surface.h | 44 | ||||
-rw-r--r-- | libs/gui/tests/BufferQueue_test.cpp | 28 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 126 |
10 files changed, 299 insertions, 8 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 528bfb194e..3a7cb44450 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -166,7 +166,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, mCore->mFreeBuffers.push_back(front->mSlot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } ++numDroppedBuffers; } @@ -457,7 +459,9 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mCore->mFreeBuffers.push_back(slot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } BQ_LOGV("releaseBuffer: releasing slot %d", slot); mCore->mDequeueCondition.notify_all(); @@ -668,7 +672,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0) { + if (delta < 0 && mCore->mBufferReleasedCbEnabled) { listener = mCore->mConsumerListener; } } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..0264bd24a6 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -65,6 +65,7 @@ BufferQueueCore::BufferQueueCore() : mConnectedApi(NO_CONNECTED_API), mLinkedToDeath(), mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), mSlots(), mQueue(), mFreeSlots(), @@ -260,6 +261,12 @@ void BufferQueueCore::freeAllBuffersLocked() { } void BufferQueueCore::discardFreeBuffersLocked() { + // Notify producer about the discarded buffers. + if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) { + std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end()); + mConnectedProducerListener->onBuffersDiscarded(freeBuffers); + } + for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 92ab41019e..a317aaf2f2 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1221,9 +1221,8 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, } mCore->mLinkedToDeath = listener; } - if (listener->needsReleaseNotify()) { - mCore->mConnectedProducerListener = listener; - } + mCore->mConnectedProducerListener = listener; + mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } break; default: diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 936063a5bd..808e3369f1 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -24,6 +24,7 @@ namespace android { enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, NEEDS_RELEASE_NOTIFY, + ON_BUFFERS_DISCARDED, }; class BpProducerListener : public BpInterface<IProducerListener> @@ -56,6 +57,13 @@ public: } return result; } + + virtual void onBuffersDiscarded(const std::vector<int>& discardedSlots) { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + data.writeInt32Vector(discardedSlots); + remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -76,6 +84,10 @@ public: virtual bool needsReleaseNotify() override { return mBase->needsReleaseNotify(); } + + virtual void onBuffersDiscarded(const std::vector<int32_t>& discardedSlots) override { + return mBase->onBuffersDiscarded(discardedSlots); + } }; IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener, @@ -92,6 +104,17 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, CHECK_INTERFACE(IProducerListener, data, reply); reply->writeBool(needsReleaseNotify()); return NO_ERROR; + case ON_BUFFERS_DISCARDED: { + CHECK_INTERFACE(IProducerListener, data, reply); + std::vector<int32_t> discardedSlots; + status_t result = data.readInt32Vector(&discardedSlots); + if (result != NO_ERROR) { + ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result); + return result; + } + onBuffersDiscarded(discardedSlots); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -104,4 +127,7 @@ bool BnProducerListener::needsReleaseNotify() { return true; } +void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) { +} + } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9fe5de82d1..b822319d22 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -35,6 +35,7 @@ #include <ui/DisplayStatInfo.h> #include <ui/Fence.h> +#include <ui/GraphicBuffer.h> #include <ui/HdrCapabilities.h> #include <ui/Region.h> @@ -1287,6 +1288,14 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) { } int Surface::connect( + int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) { + if (sListener != nullptr) { + mListenerProxy = new ProducerListenerProxy(this, sListener); + } + return connect(api, mListenerProxy, reportBufferRemoval); +} + +int Surface::connect( int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) { ATRACE_CALL(); ALOGV("Surface::connect"); @@ -1684,6 +1693,28 @@ void Surface::freeAllBuffers() { } } +status_t Surface::getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots, + std::vector<sp<GraphicBuffer>>* outBuffers) { + ALOGV("Surface::getAndFlushBuffersFromSlots"); + for (int32_t i : slots) { + if (i < 0 || i >= NUM_BUFFER_SLOTS) { + ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i); + return BAD_VALUE; + } + } + + Mutex::Autolock lock(mMutex); + for (int32_t i : slots) { + if (mSlots[i].buffer == nullptr) { + ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i); + continue; + } + outBuffers->push_back(mSlots[i].buffer); + mSlots[i].buffer = nullptr; + } + return OK; +} + void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { ATRACE_CALL(); ALOGV("Surface::setSurfaceDamage"); @@ -1951,4 +1982,22 @@ status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<Graphic return err; } +void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_t>& slots) { + ATRACE_CALL(); + sp<Surface> parent = mParent.promote(); + if (parent == nullptr) { + return; + } + + std::vector<sp<GraphicBuffer>> discardedBufs; + status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs); + if (res != OK) { + ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__, + strerror(-res), res); + return; + } + + mSurfaceListener->onBuffersDiscarded(discardedBufs); +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..17617bce13 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -189,8 +189,12 @@ private: sp<IProducerListener> mLinkedToDeath; // mConnectedProducerListener is used to handle the onBufferReleased - // notification. + // and onBuffersDiscarded notification. sp<IProducerListener> mConnectedProducerListener; + // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased() + // callback is registered by the listener. When set to false, + // mConnectedProducerListener will not trigger onBufferReleased() callback. + bool mBufferReleasedCbEnabled; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index a13d8e4945..32a3690ff2 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H +#include <vector> + #include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h> #include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h> #include <binder/IInterface.h> @@ -44,6 +46,9 @@ public: // multiple threads. virtual void onBufferReleased() = 0; // Asynchronous virtual bool needsReleaseNotify() = 0; + // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers + // to notify the producer that certain free buffers are discarded by the consumer. + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous }; class IProducerListener : public ProducerListener, public IInterface @@ -65,6 +70,7 @@ public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); }; class DummyProducerListener : public BnProducerListener diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 5c6a1ee383..a5641b07e5 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -20,6 +20,7 @@ #include <gui/BufferQueueDefs.h> #include <gui/HdrMetadata.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/IProducerListener.h> #include <ui/ANativeObjectBase.h> #include <ui/GraphicTypes.h> @@ -35,6 +36,21 @@ namespace android { class ISurfaceComposer; +/* This is the same as ProducerListener except that onBuffersDiscarded is + * called with a vector of graphic buffers instead of buffer slots. + */ +class SurfaceListener : public virtual RefBase +{ +public: + SurfaceListener() = default; + virtual ~SurfaceListener() = default; + + virtual void onBufferReleased() = 0; + virtual bool needsReleaseNotify() = 0; + + virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) = 0; +}; + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -283,6 +299,10 @@ public: sp<Fence>* outFence); virtual int attachBuffer(ANativeWindowBuffer*); + virtual int connect( + int api, bool reportBufferRemoval, + const sp<SurfaceListener>& sListener); + // When client connects to Surface with reportBufferRemoval set to true, any buffers removed // from this Surface will be collected and returned here. Once this method returns, these // buffers will no longer be referenced by this Surface unless they are attached to this @@ -299,6 +319,26 @@ protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; + class ProducerListenerProxy : public BnProducerListener { + public: + ProducerListenerProxy(wp<Surface> parent, sp<SurfaceListener> listener) + : mParent(parent), mSurfaceListener(listener) {} + virtual ~ProducerListenerProxy() {} + + virtual void onBufferReleased() { + mSurfaceListener->onBufferReleased(); + } + + virtual bool needsReleaseNotify() { + return mSurfaceListener->needsReleaseNotify(); + } + + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); + private: + wp<Surface> mParent; + sp<SurfaceListener> mSurfaceListener; + }; + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -466,6 +506,10 @@ protected: bool mReportRemovedBuffers = false; std::vector<sp<GraphicBuffer>> mRemovedBuffers; + + sp<IProducerListener> mListenerProxy; + status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots, + std::vector<sp<GraphicBuffer>>* outBuffers); }; } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..406f21faf6 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -998,12 +998,31 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { ASSERT_EQ(true, thirdSegment.usedThirdBuffer); } +struct BufferDiscardedListener : public BnProducerListener { +public: + BufferDiscardedListener() = default; + virtual ~BufferDiscardedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return false; } + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) { + mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end()); + } + + const std::vector<int32_t>& getDiscardedSlots() const { return mDiscardedSlots; } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + std::vector<int32_t> mDiscardedSlots; +}; + TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + sp<BufferDiscardedListener> pl(new BufferDiscardedListener); + ASSERT_EQ(OK, mProducer->connect(pl, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -1044,12 +1063,19 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); + int releasedSlot = item.mSlot; + // Acquire 1 buffer, leaving 1 filled buffer in queue ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); // Now discard the free buffers ASSERT_EQ(OK, mConsumer->discardFreeBuffers()); + // Check onBuffersDiscarded is called with correct slots + auto buffersDiscarded = pl->getDiscardedSlots(); + ASSERT_EQ(buffersDiscarded.size(), 1); + ASSERT_EQ(buffersDiscarded[0], releasedSlot); + // Check no free buffers in dump String8 dumpString; mConsumer->dumpState(String8{}, &dumpString); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d3708586f5..a8516872fd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -57,6 +57,37 @@ class FakeProducerFrameEventHistory; static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); +class DummySurfaceListener : public SurfaceListener { +public: + DummySurfaceListener(bool enableReleasedCb = false) : + mEnableReleaseCb(enableReleasedCb), + mBuffersReleased(0) {} + virtual ~DummySurfaceListener() = default; + + virtual void onBufferReleased() { + mBuffersReleased++; + } + virtual bool needsReleaseNotify() { + return mEnableReleaseCb; + } + virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) { + mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end()); + } + + int getReleaseNotifyCount() const { + return mBuffersReleased; + } + const std::vector<sp<GraphicBuffer>>& getDiscardedBuffers() const { + return mDiscardedBuffers; + } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + bool mEnableReleaseCb; + int32_t mBuffersReleased; + std::vector<sp<GraphicBuffer>> mDiscardedBuffers; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -88,6 +119,86 @@ protected: mComposerClient->dispose(); } + void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb, + int32_t extraDiscardedBuffers) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + sp<DummySurfaceListener> listener; + if (hasSurfaceListener) { + listener = new DummySurfaceListener(enableReleasedCb); + } + ASSERT_EQ(OK, surface->connect( + NATIVE_WINDOW_API_CPU, + /*reportBufferRemoval*/true, + /*listener*/listener)); + const int BUFFER_COUNT = 4 + extraDiscardedBuffers; + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + ANativeWindowBuffer* buffers[BUFFER_COUNT]; + // Dequeue first to allocate a number of buffers + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i])); + } + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1)); + } + + ANativeWindowBuffer* buffer; + // Fill BUFFER_COUNT-1 buffers + for (int i = 0; i < BUFFER_COUNT-1; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1)); + } + + // Dequeue 1 buffer + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + + // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called. + std::vector<BufferItem> releasedItems; + releasedItems.resize(1+extraDiscardedBuffers); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0)); + ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot, + releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE)); + } + int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0); + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue + BufferItem item; + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0)); + + // Discard free buffers + ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers()); + + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + + // Check onBufferDiscarded is called with correct buffer + auto discardedBuffers = listener->getDiscardedBuffers(); + ASSERT_EQ(discardedBuffers.size(), releasedItems.size()); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer); + } + + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Disconnect the surface + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); + } + sp<Surface> mSurface; sp<SurfaceComposerClient> mComposerClient; sp<SurfaceControl> mSurfaceControl; @@ -480,6 +591,21 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { ASSERT_LE(removedBuffers.size(), 1u); } +TEST_F(SurfaceTest, SurfaceListenerTest) { + // Test discarding 1 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0); + // Test discarding 3 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2); +} + TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { sp<ANativeWindow> anw(mSurface); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); |