surfaceflinger: move SurfaceFlingerConsumer::mPendingRelease
Move it and related methods to the base class, BufferLayerConsumer.
Test: boots
Change-Id: Ibe4d180aefbeeb3662fa40ca044d9d6fdd3b5765
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 0303d94..110b7de 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 @@
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 @@
// 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 @@
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 b8b3874..0da73d1 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 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 @@
// 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 @@
// 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 @@
// 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 38b0057..1bb9028 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -33,80 +33,6 @@
// ---------------------------------------------------------------------------
-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 @@
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 3a6beae..f4c594a 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -32,34 +32,15 @@
*/
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 @@
// 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 @@
// 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;
};
// ----------------------------------------------------------------------------