diff options
author | 2017-11-27 14:51:06 -0800 | |
---|---|---|
committer | 2017-12-11 11:11:27 -0800 | |
commit | da5c730799cb60dfb9d64f31a5f59dc892fe0ce0 (patch) | |
tree | fc08a025339ae1729699de2852bfc8334160eca4 | |
parent | fd257f86996bcf510be5f858e1ce2f8986e63435 (diff) |
surfaceflinger: move SurfaceFlingerConsumer::mPendingRelease
Move it and related methods to the base class, BufferLayerConsumer.
Test: boots
Change-Id: Ibe4d180aefbeeb3662fa40ca044d9d6fdd3b5765
-rw-r--r-- | services/surfaceflinger/BufferLayerConsumer.cpp | 137 | ||||
-rw-r--r-- | services/surfaceflinger/BufferLayerConsumer.h | 29 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlingerConsumer.cpp | 154 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlingerConsumer.h | 27 |
4 files changed, 144 insertions, 203 deletions
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 0303d94340..110b7de41a 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -21,6 +21,7 @@ #include "BufferLayerConsumer.h" +#include "DispSync.h" #include "Layer.h" #include <inttypes.h> @@ -149,7 +150,56 @@ void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedLis mContentsChangedListener = listener; } -status_t BufferLayerConsumer::updateTexImage() { +// We need to determine the time when a buffer acquired now will be +// displayed. This can be calculated: +// time when previous buffer's actual-present fence was signaled +// + current display refresh rate * HWC latency +// + a little extra padding +// +// Buffer producers are expected to set their desired presentation time +// based on choreographer time stamps, which (coming from vsync events) +// will be slightly later then the actual-present timing. If we get a +// desired-present time that is unintentionally a hair after the next +// vsync, we'll hold the frame when we really want to display it. We +// need to take the offset between actual-present and reported-vsync +// into account. +// +// If the system is configured without a DispSync phase offset for the app, +// we also want to throw in a bit of padding to avoid edge cases where we +// just barely miss. We want to do it here, not in every app. A major +// source of trouble is the app's use of the display's ideal refresh time +// (via Display.getRefreshRate()), which could be off of the actual refresh +// by a few percent, with the error multiplied by the number of frames +// between now and when the buffer should be displayed. +// +// If the refresh reported to the app has a phase offset, we shouldn't need +// to tweak anything here. +nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) { + // The HWC doesn't currently have a way to report additional latency. + // Assume that whatever we submit now will appear right after the flip. + // For a smart panel this might be 1. This is expressed in frames, + // rather than time, because we expect to have a constant frame delay + // regardless of the refresh rate. + const uint32_t hwcLatency = 0; + + // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). + const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency); + + // The DispSync time is already adjusted for the difference between + // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so + // we don't need to factor that in here. Pad a little to avoid + // weird effects if apps might be requesting times right on the edge. + nsecs_t extraPadding = 0; + if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) { + extraPadding = 1000000; // 1ms (6% of 60Hz) + } + + return nextRefresh + extraPadding; +} + +status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, + bool* autoRefresh, bool* queuedBuffer, + uint64_t maxFrameNumber) { ATRACE_CALL(); BLC_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); @@ -170,29 +220,86 @@ status_t BufferLayerConsumer::updateTexImage() { // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item, 0); + err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - // We always bind the texture even if we don't update its contents. - BLC_LOGV("updateTexImage: no buffers were available"); - glBindTexture(sTexTarget, mTexName); err = NO_ERROR; + } else if (err == BufferQueue::PRESENT_LATER) { + // return the error, without logging } else { BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); } return err; } + if (autoRefresh) { + *autoRefresh = item.mAutoRefresh; + } + + if (queuedBuffer) { + *queuedBuffer = item.mQueuedBuffer; + } + + // We call the rejecter here, in case the caller has a reason to + // not accept this buffer. This is used by SurfaceFlinger to + // reject buffers which have the wrong size + int slot = item.mSlot; + if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); + return BUFFER_REJECTED; + } + // Release the previous buffer. - err = updateAndReleaseLocked(item); + err = updateAndReleaseLocked(item, &mPendingRelease); if (err != NO_ERROR) { - // We always bind the texture. - glBindTexture(sTexTarget, mTexName); return err; } - // Bind the new buffer to the GL texture, and wait until it's ready. - return bindTextureImageLocked(); + if (!SyncFeatures::getInstance().useNativeFenceSync()) { + // Bind the new buffer to the GL texture. + // + // Older devices require the "implicit" synchronization provided + // by glEGLImageTargetTexture2DOES, which this method calls. Newer + // devices will either call this in Layer::onDraw, or (if it's not + // a GL-composited layer) not at all. + err = bindTextureImageLocked(); + } + + return err; +} + +void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { + if (!fence->isValid()) { + return; + } + + auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture; + if (slot == BufferQueue::INVALID_BUFFER_SLOT) { + return; + } + + auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer + : mCurrentTextureImage->graphicBuffer(); + auto err = addReleaseFence(slot, buffer, fence); + if (err != OK) { + BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); + } +} + +bool BufferLayerConsumer::releasePendingBuffer() { + if (!mPendingRelease.isPending) { + BLC_LOGV("Pending buffer already released"); + return false; + } + BLC_LOGV("Releasing pending buffer"); + Mutex::Autolock lock(mMutex); + status_t result = + releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer); + if (result < NO_ERROR) { + BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result); + } + mPendingRelease = PendingRelease(); + return true; } status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, @@ -351,16 +458,6 @@ status_t BufferLayerConsumer::checkAndUpdateEglStateLocked() { return NO_ERROR; } -void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { - if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = - addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); - if (err != OK) { - BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); - } - } -} - status_t BufferLayerConsumer::syncForReleaseLocked(EGLDisplay dpy) { BLC_LOGV("syncForReleaseLocked"); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index b8b3874c66..0da73d1ffe 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -33,6 +33,7 @@ namespace android { // ---------------------------------------------------------------------------- +class DispSync; class Layer; class String8; @@ -54,6 +55,16 @@ class String8; */ class BufferLayerConsumer : public ConsumerBase { public: + static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; + + class BufferRejecter { + friend class BufferLayerConsumer; + virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0; + + protected: + virtual ~BufferRejecter() {} + }; + struct ContentsChangedListener : public FrameAvailableListener { virtual void onSidebandStreamChanged() = 0; }; @@ -67,6 +78,8 @@ public: // ConsumerBase::setFrameAvailableListener(). void setContentsChangedListener(const wp<ContentsChangedListener>& listener); + nsecs_t computeExpectedPresent(const DispSync& dispSync); + // updateTexImage acquires the most recently queued buffer, and sets the // image contents of the target texture to it. // @@ -74,14 +87,22 @@ public: // target texture belongs is bound to the calling thread. // // This calls doGLFenceWait to ensure proper synchronization. - status_t updateTexImage(); + // + // This version of updateTexImage() takes a functor that may be used to + // reject the newly acquired buffer. Unlike the GLConsumer version, + // this does not guarantee that the buffer has been bound to the GL + // texture. + status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh, + bool* queuedBuffer, uint64_t maxFrameNumber); // setReleaseFence stores a fence that will signal when the current buffer // is no longer being read. This fence will be returned to the producer // when the current buffer is released by updateTexImage(). Multiple // fences can be set for a given buffer; they will be merged into a single // union fence. - virtual void setReleaseFence(const sp<Fence>& fence); + void setReleaseFence(const sp<Fence>& fence); + + bool releasePendingBuffer(); // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix // associated with the texture image set by the most recent call to @@ -384,6 +405,10 @@ private: // that no buffer is bound to the texture. A call to setBufferCount will // reset mCurrentTexture to INVALID_BUFFER_SLOT. int mCurrentTexture; + + // A release that is pending on the receipt of a new release fence from + // presentDisplay + PendingRelease mPendingRelease; }; // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 38b00579d0..1bb9028cae 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -33,80 +33,6 @@ namespace android { // --------------------------------------------------------------------------- -status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber) -{ - ATRACE_CALL(); - ALOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("updateTexImage: BufferLayerConsumer is abandoned!"); - return NO_INIT; - } - - // Make sure the EGL state is the same as in previous calls. - status_t err = checkAndUpdateEglStateLocked(); - if (err != NO_ERROR) { - return err; - } - - BufferItem item; - - // Acquire the next buffer. - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), - maxFrameNumber); - if (err != NO_ERROR) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - err = NO_ERROR; - } else if (err == BufferQueue::PRESENT_LATER) { - // return the error, without logging - } else { - ALOGE("updateTexImage: acquire failed: %s (%d)", - strerror(-err), err); - } - return err; - } - - if (autoRefresh) { - *autoRefresh = item.mAutoRefresh; - } - - if (queuedBuffer) { - *queuedBuffer = item.mQueuedBuffer; - } - - // We call the rejecter here, in case the caller has a reason to - // not accept this buffer. This is used by SurfaceFlinger to - // reject buffers which have the wrong size - int slot = item.mSlot; - if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { - releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); - return BUFFER_REJECTED; - } - - // Release the previous buffer. - err = updateAndReleaseLocked(item, &mPendingRelease); - if (err != NO_ERROR) { - return err; - } - - if (!SyncFeatures::getInstance().useNativeFenceSync()) { - // Bind the new buffer to the GL texture. - // - // Older devices require the "implicit" synchronization provided - // by glEGLImageTargetTexture2DOES, which this method calls. Newer - // devices will either call this in Layer::onDraw, or (if it's not - // a GL-composited layer) not at all. - err = bindTextureImageLocked(); - } - - return err; -} - status_t SurfaceFlingerConsumer::bindTextureImage() { Mutex::Autolock lock(mMutex); @@ -134,91 +60,11 @@ const Region& SurfaceFlingerConsumer::getSurfaceDamage() const { return mSurfaceDamage; } -// We need to determine the time when a buffer acquired now will be -// displayed. This can be calculated: -// time when previous buffer's actual-present fence was signaled -// + current display refresh rate * HWC latency -// + a little extra padding -// -// Buffer producers are expected to set their desired presentation time -// based on choreographer time stamps, which (coming from vsync events) -// will be slightly later then the actual-present timing. If we get a -// desired-present time that is unintentionally a hair after the next -// vsync, we'll hold the frame when we really want to display it. We -// need to take the offset between actual-present and reported-vsync -// into account. -// -// If the system is configured without a DispSync phase offset for the app, -// we also want to throw in a bit of padding to avoid edge cases where we -// just barely miss. We want to do it here, not in every app. A major -// source of trouble is the app's use of the display's ideal refresh time -// (via Display.getRefreshRate()), which could be off of the actual refresh -// by a few percent, with the error multiplied by the number of frames -// between now and when the buffer should be displayed. -// -// If the refresh reported to the app has a phase offset, we shouldn't need -// to tweak anything here. -nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync) -{ - // The HWC doesn't currently have a way to report additional latency. - // Assume that whatever we submit now will appear right after the flip. - // For a smart panel this might be 1. This is expressed in frames, - // rather than time, because we expect to have a constant frame delay - // regardless of the refresh rate. - const uint32_t hwcLatency = 0; - - // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). - const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency); - - // The DispSync time is already adjusted for the difference between - // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so - // we don't need to factor that in here. Pad a little to avoid - // weird effects if apps might be requesting times right on the edge. - nsecs_t extraPadding = 0; - if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) { - extraPadding = 1000000; // 1ms (6% of 60Hz) - } - - return nextRefresh + extraPadding; -} - sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const { Mutex::Autolock lock(mMutex); return ConsumerBase::mPrevFinalReleaseFence; } -void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) -{ - if (!mPendingRelease.isPending) { - BufferLayerConsumer::setReleaseFence(fence); - return; - } - auto currentTexture = mPendingRelease.currentTexture; - if (fence->isValid() && - currentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t result = addReleaseFence(currentTexture, - mPendingRelease.graphicBuffer, fence); - ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the" - " fence: %s (%d)", strerror(-result), result); - } -} - -bool SurfaceFlingerConsumer::releasePendingBuffer() -{ - if (!mPendingRelease.isPending) { - ALOGV("Pending buffer already released"); - return false; - } - ALOGV("Releasing pending buffer"); - Mutex::Autolock lock(mMutex); - status_t result = releaseBufferLocked(mPendingRelease.currentTexture, - mPendingRelease.graphicBuffer); - ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)", - strerror(-result), result); - mPendingRelease = PendingRelease(); - return true; -} - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 3a6beaed62..f4c594acf5 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -32,34 +32,15 @@ class Layer; */ class SurfaceFlingerConsumer : public BufferLayerConsumer { public: - static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; - SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t tex, Layer* layer) : BufferLayerConsumer(consumer, tex, layer), mTransformToDisplayInverse(false), mSurfaceDamage() {} - class BufferRejecter { - friend class SurfaceFlingerConsumer; - virtual bool reject(const sp<GraphicBuffer>& buf, - const BufferItem& item) = 0; - - protected: - virtual ~BufferRejecter() { } - }; - virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) override; - // This version of updateTexImage() takes a functor that may be used to - // reject the newly acquired buffer. Unlike the BufferLayerConsumer version, - // this does not guarantee that the buffer has been bound to the GL - // texture. - status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, - bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber); - // See BufferLayerConsumer::bindTextureImageLocked(). status_t bindTextureImage(); @@ -68,11 +49,7 @@ public: // must be called from SF main thread const Region& getSurfaceDamage() const; - nsecs_t computeExpectedPresent(const DispSync& dispSync); - sp<Fence> getPrevFinalReleaseFence() const; - virtual void setReleaseFence(const sp<Fence>& fence) override; - bool releasePendingBuffer(); private: // Indicates this buffer must be transformed by the inverse transform of the screen @@ -82,10 +59,6 @@ private: // The portion of this surface that has changed since the previous frame Region mSurfaceDamage; - - // A release that is pending on the receipt of a new release fence from - // presentDisplay - PendingRelease mPendingRelease; }; // ---------------------------------------------------------------------------- |