diff options
author | 2016-01-13 17:09:58 -0800 | |
---|---|---|
committer | 2016-02-09 17:16:33 -0800 | |
commit | ff95aabbcc6e8606acbd7933c90eeb9b8b382a21 (patch) | |
tree | cd7690fdf21486139cfff232c6ce09132d18a05b | |
parent | c5cec281654c5dee2273ce4bebd3a749c3a1119e (diff) |
Add interface for controlling single buffer auto refresh
- Adds a boolean to BufferQueue that controls whether or not auto
refresh is enabled in SurfaceFlinger when in single buffer mode.
- Adds plumbing up to ANativeWindow.
- When enabled, it will cache the shared buffer slot in Surface in
order to prevent the Binder transaction with SurfaceFlinger.
Bug 24940410
Change-Id: I83142afdc00e203f198a32288f071d926f8fda95
22 files changed, 266 insertions, 36 deletions
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h index a515f39848..6f45181345 100644 --- a/include/gui/BufferItem.h +++ b/include/gui/BufferItem.h @@ -119,8 +119,10 @@ class BufferItem : public Flattenable<BufferItem> { // previous frame Region mSurfaceDamage; - // Indicates that the BufferQueue is in single buffer mode - bool mSingleBufferMode; + // Indicates that the consumer should acquire the next frame as soon as it + // can and not wait for a frame to become available. This is only relevant + // in single buffer mode. + bool mAutoRefresh; // Indicates that this buffer was queued by the producer. When in single // buffer mode acquire() can return a BufferItem that wasn't in the queue. diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h index e2e73a0a8f..d10ba2f2c6 100644 --- a/include/gui/BufferQueueCore.h +++ b/include/gui/BufferQueueCore.h @@ -292,6 +292,11 @@ private: // consumer and producer to access the same buffer simultaneously. bool mSingleBufferMode; + // When single buffer mode is enabled, this indicates whether the consumer + // should acquire buffers even if BufferQueue doesn't indicate that they are + // available. + bool mAutoRefresh; + // When single buffer mode is enabled, this tracks which slot contains the // shared buffer. int mSingleBufferSlot; diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index dc05e9856a..312f323e5a 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -176,6 +176,9 @@ public: // See IGraphicBufferProducer::setSingleBufferMode virtual status_t setSingleBufferMode(bool singleBufferMode) override; + // See IGraphicBufferProducer::setAutoRefresh + virtual status_t setAutoRefresh(bool autoRefresh) override; + // See IGraphicBufferProducer::setDequeueTimeout virtual status_t setDequeueTimeout(nsecs_t timeout) override; diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 265728ffb1..f6b42300a4 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -531,6 +531,14 @@ public: // the producer and consumer to simultaneously access the same buffer. virtual status_t setSingleBufferMode(bool singleBufferMode) = 0; + // Used to enable/disable auto-refresh. + // + // Auto refresh has no effect outside of single buffer mode. In single + // buffer mode, when enabled, it indicates to the consumer that it should + // attempt to acquire buffers even if it is not aware of any being + // available. + virtual status_t setAutoRefresh(bool autoRefresh) = 0; + // Sets how long dequeueBuffer will wait for a buffer to become available // before returning an error (TIMED_OUT). // diff --git a/include/gui/Surface.h b/include/gui/Surface.h index f79210b0c4..3afdaae561 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -168,6 +168,7 @@ private: int dispatchSetBuffersDataSpace(va_list args); int dispatchSetSurfaceDamage(va_list args); int dispatchSetSingleBufferMode(va_list args); + int dispatchSetAutoRefresh(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -197,6 +198,7 @@ public: virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual int setAsyncMode(bool async); virtual int setSingleBufferMode(bool singleBufferMode); + virtual int setAutoRefresh(bool autoRefresh); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -331,6 +333,19 @@ private: // Stores the current generation number. See setGenerationNumber and // IGraphicBufferProducer::setGenerationNumber for more information. uint32_t mGenerationNumber; + + // Caches the values that have been passed to the producer. + bool mSingleBufferMode; + bool mAutoRefresh; + + // If in single buffer mode and auto refresh is enabled, store the shared + // buffer slot and return it for all calls to queue/dequeue without going + // over Binder. + int mSharedBufferSlot; + + // This is true if the shared buffer has already been queued/canceled. It's + // used to prevent a mismatch between the number of queue/dequeue calls. + bool mSharedBufferHasBeenQueued; }; }; // namespace android diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 036ef1ecf7..5e3924a7ee 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -38,7 +38,7 @@ BufferItem::BufferItem() : mAcquireCalled(false), mTransformToDisplayInverse(false), mSurfaceDamage(), - mSingleBufferMode(false), + mAutoRefresh(false), mQueuedBuffer(true), mIsStale(false) { } diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 92285e5811..f8b50cc3ca 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -67,7 +67,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, } bool sharedBufferAvailable = mCore->mSingleBufferMode && - mCore->mSingleBufferSlot != + mCore->mAutoRefresh && mCore->mSingleBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT; // In asynchronous mode the list is guaranteed to be one buffer deep, @@ -214,16 +214,15 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, (mCore->mSingleBufferCache.transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0; outBuffer->mSurfaceDamage = Region::INVALID_REGION; - outBuffer->mSingleBufferMode = true; outBuffer->mQueuedBuffer = false; outBuffer->mIsStale = false; + outBuffer->mAutoRefresh = mCore->mSingleBufferMode && + mCore->mAutoRefresh; } else { slot = front->mSlot; *outBuffer = *front; } - outBuffer->mSingleBufferMode = mCore->mSingleBufferMode; - ATRACE_BUFFER_INDEX(slot); BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index f785db0bd7..ba07362b70 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -79,6 +79,7 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mGenerationNumber(0), mAsyncMode(false), mSingleBufferMode(false), + mAutoRefresh(false), mSingleBufferSlot(INVALID_BUFFER_SLOT), mSingleBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9d4246482c..e065e6151d 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -806,8 +806,8 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCore->mDequeueBufferCannotBlock || (mCore->mSingleBufferMode && mCore->mSingleBufferSlot == slot); item.mSurfaceDamage = surfaceDamage; - item.mSingleBufferMode = mCore->mSingleBufferMode; item.mQueuedBuffer = true; + item.mAutoRefresh = mCore->mSingleBufferMode && mCore->mAutoRefresh; mStickyTransform = stickyTransform; @@ -1309,6 +1309,16 @@ status_t BufferQueueProducer::setSingleBufferMode(bool singleBufferMode) { return NO_ERROR; } +status_t BufferQueueProducer::setAutoRefresh(bool autoRefresh) { + ATRACE_CALL(); + BQ_LOGV("setAutoRefresh: %d", autoRefresh); + + Mutex::Autolock lock(mCore->mMutex); + + mCore->mAutoRefresh = autoRefresh; + return NO_ERROR; +} + status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) { ATRACE_CALL(); BQ_LOGV("setDequeueTimeout: %" PRId64, timeout); diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index e1abd45171..55059dd87b 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -407,7 +407,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) } // Do whatever sync ops we need to do before releasing the old slot. - if (!item.mSingleBufferMode || slot != mCurrentTexture) { + if (slot != mCurrentTexture) { err = syncForReleaseLocked(mEglDisplay); if (err != NO_ERROR) { // Release the buffer we just acquired. It's not safe to diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 2478601adf..c66694d94a 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -52,6 +52,7 @@ enum { SET_ASYNC_MODE, GET_NEXT_FRAME_NUMBER, SET_SINGLE_BUFFER_MODE, + SET_AUTO_REFRESH, SET_DEQUEUE_TIMEOUT, }; @@ -355,6 +356,18 @@ public: return result; } + virtual status_t setAutoRefresh(bool autoRefresh) { + Parcel data, reply; + data.writeInterfaceToken( + IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(autoRefresh); + status_t result = remote()->transact(SET_AUTO_REFRESH, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } + virtual status_t setDequeueTimeout(nsecs_t timeout) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); @@ -562,6 +575,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_REFRESH: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoRefresh = data.readInt32(); + status_t result = setAutoRefresh(autoRefresh); + reply->writeInt32(result); + return NO_ERROR; + } case SET_DEQUEUE_TIMEOUT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); nsecs_t timeout = data.readInt64(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 6fc55c344e..42adf90840 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,7 +44,11 @@ Surface::Surface( bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), - mGenerationNumber(0) + mGenerationNumber(0), + mSingleBufferMode(false), + mAutoRefresh(false), + mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), + mSharedBufferHasBeenQueued(false) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; @@ -232,6 +236,16 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { reqFormat = mReqFormat; reqUsage = mReqUsage; + + if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot != + BufferItem::INVALID_BUFFER_SLOT) { + sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer); + if (gbuf != NULL) { + *buffer = gbuf.get(); + *fenceFd = -1; + return OK; + } + } } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer int buf = -1; @@ -279,6 +293,15 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { } *buffer = gbuf.get(); + + if (mSingleBufferMode && mAutoRefresh) { + mSharedBufferSlot = buf; + mSharedBufferHasBeenQueued = false; + } else if (mSharedBufferSlot == buf) { + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + mSharedBufferHasBeenQueued = false; + } + return OK; } @@ -294,8 +317,19 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, } return i; } + if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { + if (fenceFd >= 0) { + close(fenceFd); + } + return OK; + } sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); mGraphicBufferProducer->cancelBuffer(i, fence); + + if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) { + mSharedBufferHasBeenQueued = true; + } + return OK; } @@ -323,6 +357,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { Mutex::Autolock lock(mMutex); int64_t timestamp; bool isAutoTimestamp = false; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); isAutoTimestamp = true; @@ -338,6 +373,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { } return i; } + if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { + if (fenceFd >= 0) { + close(fenceFd); + } + return OK; + } // Make sure the crop rectangle is entirely inside the buffer. @@ -417,6 +458,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); } + uint32_t numPendingBuffers = 0; uint32_t hint = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, @@ -434,6 +476,10 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { mDirtyRegion = Region::INVALID_REGION; } + if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) { + mSharedBufferHasBeenQueued = true; + } + return err; } @@ -557,6 +603,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE: res = dispatchSetSingleBufferMode(args); break; + case NATIVE_WINDOW_SET_AUTO_REFRESH: + res = dispatchSetAutoRefresh(args); + break; default: res = NAME_NOT_FOUND; break; @@ -669,8 +718,12 @@ int Surface::dispatchSetSurfaceDamage(va_list args) { int Surface::dispatchSetSingleBufferMode(va_list args) { bool singleBufferMode = va_arg(args, int); - setSingleBufferMode(singleBufferMode); - return NO_ERROR; + return setSingleBufferMode(singleBufferMode); +} + +int Surface::dispatchSetAutoRefresh(va_list args) { + bool autoRefresh = va_arg(args, int); + return setAutoRefresh(autoRefresh); } int Surface::connect(int api) { @@ -714,6 +767,8 @@ int Surface::disconnect(int api) { ATRACE_CALL(); ALOGV("Surface::disconnect"); Mutex::Autolock lock(mMutex); + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + mSharedBufferHasBeenQueued = false; freeAllBuffers(); int err = mGraphicBufferProducer->disconnect(api); if (!err) { @@ -796,6 +851,9 @@ int Surface::setUsage(uint32_t reqUsage) { ALOGV("Surface::setUsage"); Mutex::Autolock lock(mMutex); + if (reqUsage != mReqUsage) { + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + } mReqUsage = reqUsage; return OK; } @@ -888,12 +946,29 @@ int Surface::setSingleBufferMode(bool singleBufferMode) { status_t err = mGraphicBufferProducer->setSingleBufferMode( singleBufferMode); - ALOGE_IF(err, "IGraphicsBufferProducer::setSingleBufferMode(%d) returned" + if (err == NO_ERROR) { + mSingleBufferMode = singleBufferMode; + } + ALOGE_IF(err, "IGraphicBufferProducer::setSingleBufferMode(%d) returned" "%s", singleBufferMode, strerror(-err)); return err; } +int Surface::setAutoRefresh(bool autoRefresh) { + ATRACE_CALL(); + ALOGV("Surface::setAutoRefresh (%d)", autoRefresh); + Mutex::Autolock lock(mMutex); + + status_t err = mGraphicBufferProducer->setAutoRefresh(autoRefresh); + if (err == NO_ERROR) { + mAutoRefresh = autoRefresh; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoRefresh(%d) returned %s", + autoRefresh, strerror(-err)); + return err; +} + int Surface::setBuffersDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); @@ -903,6 +978,9 @@ int Surface::setBuffersDimensions(uint32_t width, uint32_t height) return BAD_VALUE; Mutex::Autolock lock(mMutex); + if (width != mReqWidth || height != mReqHeight) { + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + } mReqWidth = width; mReqHeight = height; return NO_ERROR; @@ -917,6 +995,9 @@ int Surface::setBuffersUserDimensions(uint32_t width, uint32_t height) return BAD_VALUE; Mutex::Autolock lock(mMutex); + if (width != mUserWidth || height != mUserHeight) { + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + } mUserWidth = width; mUserHeight = height; return NO_ERROR; @@ -927,6 +1008,9 @@ int Surface::setBuffersFormat(PixelFormat format) ALOGV("Surface::setBuffersFormat"); Mutex::Autolock lock(mMutex); + if (format != mReqFormat) { + mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; + } mReqFormat = format; return NO_ERROR; } diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index f4c47ed6f6..b6af166088 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -65,6 +65,27 @@ protected: BufferQueue::createBufferQueue(&mProducer, &mConsumer); } + void testBufferItem(const IGraphicBufferProducer::QueueBufferInput& input, + const BufferItem& item) { + int64_t timestamp; + bool isAutoTimestamp; + android_dataspace dataSpace; + Rect crop; + int scalingMode; + uint32_t transform; + sp<Fence> fence; + + input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, + &scalingMode, &transform, &fence, NULL); + ASSERT_EQ(timestamp, item.mTimestamp); + ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp); + ASSERT_EQ(dataSpace, item.mDataSpace); + ASSERT_EQ(crop, item.mCrop); + ASSERT_EQ(static_cast<uint32_t>(scalingMode), item.mScalingMode); + ASSERT_EQ(transform, item.mTransform); + ASSERT_EQ(fence, item.mFence); + } + sp<IGraphicBufferProducer> mProducer; sp<IGraphicBufferConsumer> mConsumer; }; @@ -521,7 +542,57 @@ TEST_F(BufferQueueTest, TestGenerationNumbers) { ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer)); } -TEST_F(BufferQueueTest, TestSingleBufferMode) { +TEST_F(BufferQueueTest, TestSingleBufferModeWithoutAutoRefresh) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + ASSERT_EQ(OK, mProducer->setSingleBufferMode(true)); + + // Get a buffer + int singleSlot; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&singleSlot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->requestBuffer(singleSlot, &buffer)); + + // Queue the buffer + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); + ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output)); + + // Repeatedly queue and dequeue a buffer from the producer side, it should + // always return the same one. And we won't run out of buffers because it's + // always the same one and because async mode gets enabled. + int slot; + for (int i = 0; i < 5; i++) { + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(singleSlot, slot); + ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output)); + } + + // acquire the buffer + BufferItem item; + ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); + ASSERT_EQ(singleSlot, item.mSlot); + testBufferItem(input, item); + ASSERT_EQ(true, item.mQueuedBuffer); + ASSERT_EQ(false, item.mAutoRefresh); + + ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); + + // attempt to acquire a second time should return no buffer available + ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, + mConsumer->acquireBuffer(&item, 0)); +} + +TEST_F(BufferQueueTest, TestSingleBufferModeWithAutoRefresh) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); @@ -530,6 +601,7 @@ TEST_F(BufferQueueTest, TestSingleBufferMode) { NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setSingleBufferMode(true)); + ASSERT_EQ(OK, mProducer->setAutoRefresh(true)); // Get a buffer int singleSlot; @@ -551,13 +623,9 @@ TEST_F(BufferQueueTest, TestSingleBufferMode) { for (int i = 0; i < 5; i++) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(singleSlot, item.mSlot); - ASSERT_EQ(0, item.mTimestamp); - ASSERT_EQ(false, item.mIsAutoTimestamp); - ASSERT_EQ(HAL_DATASPACE_UNKNOWN, item.mDataSpace); - ASSERT_EQ(Rect(0, 0, 1, 1), item.mCrop); - ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode); - ASSERT_EQ(0u, item.mTransform); - ASSERT_EQ(Fence::NO_FENCE, item.mFence); + testBufferItem(input, item); + ASSERT_EQ(i == 0, item.mQueuedBuffer); + ASSERT_EQ(true, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); @@ -585,6 +653,8 @@ TEST_F(BufferQueueTest, TestSingleBufferMode) { ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode); ASSERT_EQ(0u, item.mTransform); ASSERT_EQ(Fence::NO_FENCE, item.mFence); + ASSERT_EQ(i == 0, item.mQueuedBuffer); + ASSERT_EQ(true, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index c7e2afb6a4..05700f8c69 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1197,6 +1197,7 @@ EGLBoolean eglSurfaceAttrib( //XXX: temporary hack for the EGL hook-up for single buffer mode if (attribute == EGL_RENDER_BUFFER && (value == EGL_BACK_BUFFER || value == EGL_SINGLE_BUFFER)) { + native_window_set_auto_refresh(s->win.get(), true); return (native_window_set_single_buffer_mode(s->win.get(), value == EGL_SINGLE_BUFFER)) ? EGL_TRUE : EGL_FALSE; } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 64c1dd9295..1a0d6898fd 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -547,8 +547,14 @@ uint64_t VirtualDisplaySurface::getNextFrameNumber() const { return 0; } -status_t VirtualDisplaySurface::setSingleBufferMode(bool singleBufferMode) { - return mSource[SOURCE_SINK]->setSingleBufferMode(singleBufferMode); +status_t VirtualDisplaySurface::setSingleBufferMode(bool /*singleBufferMode*/) { + ALOGE("setSingleBufferMode not supported on VirtualDisplaySurface"); + return INVALID_OPERATION; +} + +status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) { + ALOGE("setAutoRefresh not supported on VirtualDisplaySurface"); + return INVALID_OPERATION; } status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 7f451a9ca8..ede204c224 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -121,6 +121,7 @@ private: virtual String8 getConsumerName() const override; virtual uint64_t getNextFrameNumber() const override; virtual status_t setSingleBufferMode(bool singleBufferMode) override; + virtual status_t setAutoRefresh(bool autoRefresh) override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; // diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d39075f825..6574898154 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -88,7 +88,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mQueueItems(), mLastFrameNumberReceived(0), mUpdateTexImageFailed(false), - mSingleBufferMode(false) + mAutoRefresh(false) { mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -1260,7 +1260,7 @@ void Layer::useEmptyDamage() { // ---------------------------------------------------------------------------- bool Layer::shouldPresentNow(const DispSync& dispSync) const { - if (mSidebandStreamChanged || mSingleBufferMode) { + if (mSidebandStreamChanged || mAutoRefresh) { return true; } @@ -1284,7 +1284,7 @@ bool Layer::shouldPresentNow(const DispSync& dispSync) const { bool Layer::onPreComposition() { mRefreshPending = false; - return mQueuedFrames > 0 || mSidebandStreamChanged || mSingleBufferMode; + return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } void Layer::onPostComposition() { @@ -1341,7 +1341,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) } Region outDirtyRegion; - if (mQueuedFrames > 0 || mSingleBufferMode) { + if (mQueuedFrames > 0 || mAutoRefresh) { // if we've already called updateTexImage() without going through // a composition step, we have to skip this layer at this point @@ -1507,7 +1507,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) // buffer mode. bool queuedBuffer = false; status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, - mFlinger->mPrimaryDispSync, &mSingleBufferMode, &queuedBuffer, + mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer, mLastFrameNumberReceived); if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a @@ -1563,7 +1563,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) // Decrement the queued-frames count. Signal another event if we // have more frames pending. if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) - || mSingleBufferMode) { + || mAutoRefresh) { mFlinger->signalLayerUpdate(); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d91e94ef67..1773dafe46 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -307,7 +307,7 @@ public: * Returns if a frame is queued. */ bool hasQueuedFrame() const { return mQueuedFrames > 0 || - mSidebandStreamChanged || mSingleBufferMode; } + mSidebandStreamChanged || mAutoRefresh; } // ----------------------------------------------------------------------- @@ -493,7 +493,7 @@ private: std::atomic<uint64_t> mLastFrameNumberReceived; bool mUpdateTexImageFailed; // This is only modified from the main thread - bool mSingleBufferMode; + bool mAutoRefresh; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index efc44ab8ae..e161d9f6d7 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -135,6 +135,10 @@ status_t MonitoredProducer::setSingleBufferMode(bool singleBufferMode) { return mProducer->setSingleBufferMode(singleBufferMode); } +status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) { + return mProducer->setAutoRefresh(autoRefresh); +} + status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) { return mProducer->setDequeueTimeout(timeout); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index aea2e399d8..35ce558907 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -60,7 +60,8 @@ public: virtual uint64_t getNextFrameNumber() const override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; virtual IBinder* onAsBinder(); - virtual status_t setSingleBufferMode(bool singleBufferMode); + virtual status_t setSingleBufferMode(bool singleBufferMode) override; + virtual status_t setAutoRefresh(bool autoRefresh) override; private: sp<IGraphicBufferProducer> mProducer; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 5722fb446c..d3b66e6a2e 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -32,7 +32,7 @@ namespace android { // --------------------------------------------------------------------------- status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync, bool* singleBufferMode, bool* queuedBuffer, + const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber) { ATRACE_CALL(); @@ -78,8 +78,8 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, return BUFFER_REJECTED; } - if (singleBufferMode) { - *singleBufferMode = item.mSingleBufferMode; + if (autoRefresh) { + *autoRefresh = item.mAutoRefresh; } if (queuedBuffer) { diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 207c243c12..f3942abee9 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -57,7 +57,7 @@ public: // this does not guarantee that the buffer has been bound to the GL // texture. status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, - bool* singleBufferMode, bool* queuedBuffer, + bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber = 0); // See GLConsumer::bindTextureImageLocked(). |