summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger')
-rw-r--r--services/surfaceflinger/DispSync.cpp28
-rw-r--r--services/surfaceflinger/DispSync.h11
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp2
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp7
-rw-r--r--services/surfaceflinger/Layer.cpp3
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp19
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.cpp63
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.h8
9 files changed, 106 insertions, 37 deletions
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 602f20a..fd46822 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -61,7 +61,10 @@ class DispSyncThread: public Thread {
public:
DispSyncThread():
+ mLowPowerMode(false),
mStop(false),
+ mLastVsyncSent(false),
+ mLastBufferFull(false),
mPeriod(0),
mPhase(0),
mWakeupLatency(0) {
@@ -145,7 +148,18 @@ public:
}
if (callbackInvocations.size() > 0) {
- fireCallbackInvocations(callbackInvocations);
+ if (mLowPowerMode) {
+ if (!mLastVsyncSent || !mLastBufferFull) {
+ fireCallbackInvocations(callbackInvocations);
+ mLastVsyncSent = true;
+ } else
+ mLastVsyncSent = false;
+ } else {
+ fireCallbackInvocations(callbackInvocations);
+ }
+ mLastBufferFull = true;
+ } else {
+ mLastBufferFull = false;
}
}
@@ -200,6 +214,7 @@ public:
return !mEventListeners.empty();
}
+ bool mLowPowerMode;
private:
struct EventListener {
@@ -272,6 +287,8 @@ private:
}
bool mStop;
+ bool mLastVsyncSent;
+ bool mLastBufferFull;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -395,6 +412,10 @@ status_t DispSync::addEventListener(nsecs_t phase,
return mThread->addEventListener(phase, callback);
}
+void DispSync::setLowPowerMode(bool enabled) {
+ mThread->mLowPowerMode = enabled;
+}
+
status_t DispSync::removeEventListener(const sp<Callback>& callback) {
Mutex::Autolock lock(mMutex);
return mThread->removeEventListener(callback);
@@ -487,4 +508,9 @@ void DispSync::resetErrorLocked() {
}
}
+nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ return (((now - mPhase) / mPeriod) + periodOffset + 1) * mPeriod + mPhase;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index c4280aa..5826a78 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -83,11 +83,14 @@ public:
bool addResyncSample(nsecs_t timestamp);
void endResync();
- // The setPreiod method sets the vsync event model's period to a specific
+ // The setPeriod method sets the vsync event model's period to a specific
// value. This should be used to prime the model when a display is first
// turned on. It should NOT be used after that.
void setPeriod(nsecs_t period);
+ // Setting the low power mode reduces the frame rate to half of the default
+ void setLowPowerMode(bool enabled);
+
// addEventListener registers a callback to be called repeatedly at the
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
@@ -99,6 +102,12 @@ public:
// DispSync object.
status_t removeEventListener(const sp<Callback>& callback);
+ // computeNextRefresh computes when the next refresh is expected to begin.
+ // The periodOffset value can be used to move forward or backward; an
+ // offset of zero is the next refresh, -1 is the previous refresh, 1 is
+ // the refresh after next. etc.
+ nsecs_t computeNextRefresh(int periodOffset) const;
+
private:
void updateModelLocked();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4dccc22..51c7059 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -848,7 +848,7 @@ status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
return NO_ERROR;
}
-sp<Fence> HWComposer::getLastRetireFence(int32_t id) {
+sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
return Fence::NO_FENCE;
return mDisplayData[id].lastRetireFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 32d4a0c..2f92672 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -142,7 +142,7 @@ public:
// signal when the h/w composer is completely finished with the frame.
// For physical displays, it is no longer being displayed. For virtual
// displays, writes to the output buffer are complete.
- sp<Fence> getLastRetireFence(int32_t id);
+ sp<Fence> getLastRetireFence(int32_t id) const;
/*
* Interface to hardware composer's layers functionality.
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1362ae8..c415560 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -302,7 +302,12 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source,
}
}
if (result & BUFFER_NEEDS_REALLOCATION) {
- mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+ result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+ if (result < 0) {
+ mProducerBuffers[pslot].clear();
+ mSource[source]->cancelBuffer(*sslot, *fence);
+ return result;
+ }
VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
mProducerBuffers[pslot]->getPixelFormat(),
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b86204..63bc257 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1095,7 +1095,8 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions);
- status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r);
+ status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
+ mFlinger->mPrimaryDispSync);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46e192e..32d173d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2394,6 +2394,15 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
result.append(SyncFeatures::getInstance().toString());
result.append("\n");
+ colorizer.bold(result);
+ result.append("DispSync configuration: ");
+ colorizer.reset(result);
+ result.appendFormat("app phase %"PRId64" ns, sf phase %"PRId64" ns, "
+ "present offset %d ns (refresh %"PRId64" ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
+ mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
+ result.append("\n");
+
/*
* Dump the visible layer list
*/
@@ -2666,6 +2675,16 @@ status_t SurfaceFlinger::onTransact(
repaintEverything();
return NO_ERROR;
}
+ // This is an experimental interface
+ // Needs to be shifted to proper binder interface when we productize
+ case 1016: {
+ mPrimaryDispSync.setLowPowerMode(true);
+ return NO_ERROR;
+ }
+ case 1017: {
+ mPrimaryDispSync.setLowPowerMode(false);
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index a412543..7de6ac4 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -29,7 +29,8 @@ namespace android {
// ---------------------------------------------------------------------------
-status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
+ const DispSync& dispSync)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -51,7 +52,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
// 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());
+ err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -128,35 +129,41 @@ sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
// 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
-// want to use an expected-presentation time that is slightly late to
-// avoid this sort of edge case.
-nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
+// 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)
{
- // Don't yet have an easy way to get actual buffer flip time for
- // the specific display, so use the current time. This is typically
- // 1.3ms past the vsync event time.
- const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC);
-
- // Given a SurfaceFlinger reference, and information about what display
- // we're destined for, we could query the HWC for the refresh rate. This
- // could change over time, e.g. we could switch to 24fps for a movie.
- // For now, assume 60fps.
- //const nsecs_t vsyncPeriod =
- // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
- const nsecs_t vsyncPeriod = 16700000;
-
// The HWC doesn't currently have a way to report additional latency.
- // Assume that whatever we submit now will appear on the next flip,
- // i.e. 1 frame of latency w.r.t. the previous flip.
- const uint32_t hwcLatency = 1;
-
- // A little extra padding to compensate for slack between actual vsync
- // time and vsync event receipt. Currently not needed since we're
- // using "now" instead of a vsync time.
- const nsecs_t extraPadding = 0;
+ // 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 (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), 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 (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
+ extraPadding = 1000000; // 1ms (6% of 60Hz)
+ }
- // Total it up.
- return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
+ return nextRefresh + extraPadding;
}
void SurfaceFlingerConsumer::setContentsChangedListener(
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 0f1bf35..ed307c2 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SURFACEFLINGERCONSUMER_H
#define ANDROID_SURFACEFLINGERCONSUMER_H
+#include "DispSync.h"
#include <gui/GLConsumer.h>
namespace android {
@@ -33,7 +34,8 @@ public:
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
uint32_t tex)
- : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false)
+ : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false),
+ mTransformToDisplayInverse(false)
{}
class BufferRejecter {
@@ -51,7 +53,7 @@ public:
// 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);
+ status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
@@ -66,7 +68,7 @@ public:
sp<NativeHandle> getSidebandStream() const;
private:
- nsecs_t computeExpectedPresent();
+ nsecs_t computeExpectedPresent(const DispSync& dispSync);
virtual void onSidebandStreamChanged();