Merge changes I2f5c4d68,I65d5bd14 into main
* changes:
[legacy sf flag] - Remove legacy methods for front end
[legacy sf flag] - Remove layerLifecycleManagerEnabled
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 0f251d2..d85182d 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -112,13 +112,15 @@
std::string iface;
std::string instance;
- static bool fill(const std::string& name, AidlName* aname) {
+ static bool fill(const std::string& name, AidlName* aname, bool logError) {
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
- ALOGE("VINTF HALs require names in the format type/instance (e.g. "
- "some.package.foo.IFoo/default) but got: %s",
- name.c_str());
+ if (logError) {
+ ALOGE("VINTF HALs require names in the format type/instance (e.g. "
+ "some.package.foo.IFoo/default) but got: %s",
+ name.c_str());
+ }
return false;
}
aname->package = name.substr(0, lastDot);
@@ -151,7 +153,7 @@
}
AidlName aname;
- if (!AidlName::fill(name, &aname)) return false;
+ if (!AidlName::fill(name, &aname, true)) return false;
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
@@ -209,7 +211,7 @@
}
AidlName aname;
- if (!AidlName::fill(name, &aname)) return std::nullopt;
+ if (!AidlName::fill(name, &aname, true)) return std::nullopt;
std::optional<std::string> updatableViaApex;
@@ -251,7 +253,7 @@
static std::optional<std::string> getVintfAccessorName(const std::string& name) {
AidlName aname;
- if (!AidlName::fill(name, &aname)) return std::nullopt;
+ if (!AidlName::fill(name, &aname, false)) return std::nullopt;
std::optional<std::string> accessor;
forEachManifest([&](const ManifestWithDescription& mwd) {
@@ -270,7 +272,7 @@
static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
AidlName aname;
- if (!AidlName::fill(name, &aname)) return std::nullopt;
+ if (!AidlName::fill(name, &aname, true)) return std::nullopt;
std::optional<std::string> ip;
std::optional<uint64_t> port;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 87fd448..685391e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,8 +44,6 @@
#include <gui/AidlStatusUtil.h>
#include <gui/BufferItem.h>
-#include <gui/IProducerListener.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
@@ -1860,30 +1858,31 @@
}
int Surface::connect(int api) {
- static sp<IProducerListener> listener = new StubProducerListener();
+ static sp<SurfaceListener> listener = new StubSurfaceListener();
return connect(api, listener);
}
-int Surface::connect(int api, const sp<IProducerListener>& listener) {
+int Surface::connect(int api, const sp<SurfaceListener>& listener) {
return connect(api, listener, false);
}
int Surface::connect(
int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) {
- if (sListener != nullptr) {
- mListenerProxy = new ProducerListenerProxy(this, sListener);
- }
- return connect(api, mListenerProxy, reportBufferRemoval);
+ return connect(api, sListener, reportBufferRemoval);
}
-int Surface::connect(
- int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
+int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBufferRemoval) {
ATRACE_CALL();
ALOGV("Surface::connect");
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
mReportRemovedBuffers = reportBufferRemoval;
- int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
+ if (listener != nullptr) {
+ mListenerProxy = new ProducerListenerProxy(this, listener);
+ }
+
+ int err =
+ mGraphicBufferProducer->connect(mListenerProxy, api, mProducerControlledByApp, &output);
if (err == NO_ERROR) {
mDefaultWidth = output.width;
mDefaultHeight = output.height;
@@ -1911,7 +1910,6 @@
return err;
}
-
int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
ATRACE_CALL();
ALOGV("Surface::disconnect");
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index bdcaaf2..1245501 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -56,6 +56,16 @@
virtual bool needsReleaseNotify() = 0;
virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) = 0;
+ virtual void onBufferDetached(int slot) = 0;
+};
+
+class StubSurfaceListener : public SurfaceListener {
+public:
+ virtual ~StubSurfaceListener() {}
+ virtual void onBufferReleased() override {}
+ virtual bool needsReleaseNotify() { return false; }
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /*buffers*/) override {}
+ virtual void onBufferDetached(int /*slot*/) override {}
};
/*
@@ -357,15 +367,13 @@
virtual int unlockAndPost();
virtual int query(int what, int* value) const;
- virtual int connect(int api, const sp<IProducerListener>& listener);
+ virtual int connect(int api, const sp<SurfaceListener>& listener);
// When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch
// GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or
// attachBuffer call. This allows clients with their own buffer caches to free up buffers no
// longer in use by this surface.
- virtual int connect(
- int api, const sp<IProducerListener>& listener,
- bool reportBufferRemoval);
+ virtual int connect(int api, const sp<SurfaceListener>& listener, bool reportBufferRemoval);
virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence);
virtual int attachBuffer(ANativeWindowBuffer*);
@@ -422,6 +430,8 @@
return mSurfaceListener->needsReleaseNotify();
}
+ virtual void onBufferDetached(int slot) { mSurfaceListener->onBufferDetached(slot); }
+
virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
private:
wp<Surface> mParent;
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 946ff05..6852589 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -1269,6 +1269,20 @@
}
};
+class TestSurfaceListener : public SurfaceListener {
+public:
+ sp<IGraphicBufferProducer> mIgbp;
+ TestSurfaceListener(const sp<IGraphicBufferProducer>& igbp) : mIgbp(igbp) {}
+ void onBufferReleased() override {
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ mIgbp->detachNextBuffer(&buffer, &fence);
+ }
+ bool needsReleaseNotify() override { return true; }
+ void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /*buffers*/) override {}
+ void onBufferDetached(int /*slot*/) {}
+};
+
TEST_F(BLASTBufferQueueTest, CustomProducerListener) {
BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
sp<IGraphicBufferProducer> igbProducer = adapter.getIGraphicBufferProducer();
@@ -1327,7 +1341,7 @@
ASSERT_EQ(ui::Transform::ROT_0, static_cast<ui::Transform::RotationFlags>(transformHint));
ASSERT_EQ(NO_ERROR,
- surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer)));
+ surface->connect(NATIVE_WINDOW_API_CPU, new TestSurfaceListener(igbProducer)));
// After connecting to the surface, we should get the correct hint.
surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ace4423..f7a8212 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -27,7 +27,6 @@
#include <configstore/Utils.h>
#include <gui/AidlStatusUtil.h>
#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -82,7 +81,7 @@
virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) {
mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end());
}
-
+ virtual void onBufferDetached(int /*slot*/) {}
int getReleaseNotifyCount() const {
return mBuffersReleased;
}
@@ -491,7 +490,7 @@
sp<Surface> surface = new Surface(producer);
sp<ANativeWindow> window(surface);
- sp<StubProducerListener> listener = new StubProducerListener();
+ sp<StubSurfaceListener> listener = new StubSurfaceListener();
ASSERT_EQ(OK, surface->connect(
NATIVE_WINDOW_API_CPU,
/*listener*/listener,
@@ -2154,7 +2153,7 @@
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<Surface> surface = new Surface(producer);
sp<ANativeWindow> window(surface);
- sp<StubProducerListener> listener = new StubProducerListener();
+ sp<StubSurfaceListener> listener = new StubSurfaceListener();
ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener,
/*reportBufferRemoval*/false));
@@ -2206,7 +2205,7 @@
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<Surface> surface = new Surface(producer);
sp<ANativeWindow> window(surface);
- sp<StubProducerListener> listener = new StubProducerListener();
+ sp<StubSurfaceListener> listener = new StubSurfaceListener();
ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener,
/*reportBufferRemoval*/false));
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3fc3901..ee7eda1 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -487,13 +487,13 @@
return 0ns;
}
-void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime,
- TimePoint lastConfirmedPresentTime) {
+void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, FrameTime lastSignaledFrameTime) {
SFTRACE_NAME("VSyncPredictor::onFrameBegin");
std::lock_guard lock(mMutex);
if (!mDisplayModePtr->getVrrConfig()) return;
+ const auto [lastConfirmedPresentTime, lastConfirmedExpectedPresentTime] = lastSignaledFrameTime;
if (CC_UNLIKELY(mTraceOn)) {
SFTRACE_FORMAT_INSTANT("vsync is %.2f past last signaled fence",
static_cast<float>(expectedPresentTime.ns() -
@@ -519,6 +519,11 @@
}
}
+ if (lastConfirmedExpectedPresentTime.ns() - lastConfirmedPresentTime.ns() > threshold) {
+ SFTRACE_FORMAT_INSTANT("lastFramePresentedEarly");
+ return;
+ }
+
const auto phase = ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime);
if (phase > 0ns) {
mMissedVsync = {expectedPresentTime, minFramePeriodLocked()};
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 64e1029..9e1c90b 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -22,6 +22,7 @@
#include <vector>
#include <android-base/thread_annotations.h>
+#include <scheduler/FrameTime.h>
#include <scheduler/TimeKeeper.h>
#include <ui/DisplayId.h>
@@ -77,7 +78,7 @@
void setRenderRate(Fps, bool applyImmediately) final EXCLUDES(mMutex);
- void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) final
+ void onFrameBegin(TimePoint expectedPresentTime, FrameTime lastSignaledFrameTime) final
EXCLUDES(mMutex);
void onFrameMissed(TimePoint expectedPresentTime) final EXCLUDES(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 134d28e..3376fad 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -21,6 +21,7 @@
#include <scheduler/Fps.h>
#include <scheduler/FrameRateMode.h>
+#include <scheduler/FrameTime.h>
#include "VSyncDispatch.h"
@@ -112,8 +113,7 @@
*/
virtual void setRenderRate(Fps, bool applyImmediately) = 0;
- virtual void onFrameBegin(TimePoint expectedPresentTime,
- TimePoint lastConfirmedPresentTime) = 0;
+ virtual void onFrameBegin(TimePoint expectedPresentTime, FrameTime lastSignaledFrameTime) = 0;
virtual void onFrameMissed(TimePoint expectedPresentTime) = 0;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index d37d2dc..38cb446 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -26,6 +26,7 @@
#include <ui/FenceTime.h>
#include <scheduler/Features.h>
+#include <scheduler/FrameTime.h>
#include <scheduler/Time.h>
#include <scheduler/VsyncId.h>
#include <scheduler/interface/CompositeResult.h>
@@ -57,13 +58,6 @@
// The time of the VSYNC that preceded this frame. See `presentFenceForPastVsync` for details.
TimePoint pastVsyncTime(Period minFramePeriod) const;
- // The present fence for the frame that had targeted the most recent VSYNC before this frame.
- // If the target VSYNC for any given frame is more than `vsyncPeriod` in the future, then the
- // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the
- // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been
- // signaled by now (unless that frame missed).
- FenceTimePtr presentFenceForPastVsync(Period minFramePeriod) const;
-
// Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead.
const FenceTimePtr& presentFenceForPreviousFrame() const {
return mPresentFences.front().fenceTime;
@@ -72,7 +66,7 @@
bool isFramePending() const { return mFramePending; }
bool didMissFrame() const { return mFrameMissed; }
bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; }
- TimePoint lastSignaledFrameTime() const { return mLastSignaledFrameTime; };
+ FrameTime lastSignaledFrameTime() const { return mLastSignaledFrameTime; }
protected:
explicit FrameTarget(const std::string& displayLabel);
@@ -106,10 +100,17 @@
FenceTimePtr fenceTime = FenceTime::NO_FENCE;
TimePoint expectedPresentTime = TimePoint();
};
+
+ // The present fence for the frame that had targeted the most recent VSYNC before this frame.
+ // If the target VSYNC for any given frame is more than `vsyncPeriod` in the future, then the
+ // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the
+ // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been
+ // signaled by now (unless that frame missed).
+ FenceWithFenceTime presentFenceForPastVsync(Period minFramePeriod) const;
std::array<FenceWithFenceTime, 2> mPresentFences;
utils::RingBuffer<FenceWithFenceTime, 5> mFenceWithFenceTimes;
- TimePoint mLastSignaledFrameTime;
+ FrameTime mLastSignaledFrameTime;
private:
friend class FrameTargeterTestBase;
@@ -120,16 +121,17 @@
return expectedFrameDuration() > (N - 1) * minFramePeriod;
}
- const FenceTimePtr pastVsyncTimePtr() const {
- auto pastFenceTimePtr = FenceTime::NO_FENCE;
+ FenceWithFenceTime pastVsyncTimePtr() const {
+ FenceWithFenceTime pastFenceWithFenceTime;
for (size_t i = 0; i < mFenceWithFenceTimes.size(); i++) {
- const auto& [_, fenceTimePtr, expectedPresentTime] = mFenceWithFenceTimes[i];
- if (expectedPresentTime > mFrameBeginTime) {
- return pastFenceTimePtr;
+ const auto& fenceWithFenceTime = mFenceWithFenceTimes[i];
+ // TODO(b/354007767) Fix the below condition to avoid frame drop
+ if (fenceWithFenceTime.expectedPresentTime > mFrameBeginTime) {
+ return pastFenceWithFenceTime;
}
- pastFenceTimePtr = fenceTimePtr;
+ pastFenceWithFenceTime = fenceWithFenceTime;
}
- return pastFenceTimePtr;
+ return pastFenceWithFenceTime;
}
};
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTime.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTime.h
new file mode 100644
index 0000000..ed5c899
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTime.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <scheduler/Time.h>
+
+namespace android::scheduler {
+struct FrameTime {
+ TimePoint signalTime;
+ TimePoint expectedPresentTime;
+};
+} // namespace android::scheduler
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
index 60694b9..1d248fb 100644
--- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
+++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
@@ -33,12 +33,12 @@
return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
}
-FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
+FrameTarget::FenceWithFenceTime FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
return pastVsyncTimePtr();
}
const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
- return mPresentFences[i].fenceTime;
+ return mPresentFences[i];
}
bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
@@ -51,7 +51,7 @@
return true;
}
- const auto fence = presentFenceForPastVsync(minFramePeriod);
+ const auto fence = presentFenceForPastVsync(minFramePeriod).fenceTime;
return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
@@ -93,7 +93,7 @@
ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
- const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod);
+ FenceWithFenceTime pastPresentFence = presentFenceForPastVsync(minFramePeriod);
// In cases where the present fence is about to fire, give it a small grace period instead of
// giving up on the frame.
@@ -105,8 +105,8 @@
// Pending frames may trigger backpressure propagation.
const auto& isFencePending = *isFencePendingFuncPtr;
- mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
- isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
+ mFramePending = pastPresentFence.fenceTime != FenceTime::NO_FENCE &&
+ isFencePending(pastPresentFence.fenceTime, graceTimeForPresentFenceMs);
// A frame is missed if the prior frame is still pending. If no longer pending, then we still
// count the frame as missed if the predicted present time was further in the past than when the
@@ -114,9 +114,10 @@
// than a typical frame duration, but should not be so small that it reports reasonable drift as
// a missed frame.
mFrameMissed = mFramePending || [&] {
- const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
+ const nsecs_t pastPresentTime = pastPresentFence.fenceTime->getSignalTime();
if (pastPresentTime < 0) return false;
- mLastSignaledFrameTime = TimePoint::fromNs(pastPresentTime);
+ mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
+ .expectedPresentTime = pastPresentFence.expectedPresentTime};
const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
}();
diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
index 5448eec..190d062 100644
--- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
+++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
@@ -57,6 +57,10 @@
return target().wouldPresentEarly(minFramePeriod);
}
+ FrameTarget::FenceWithFenceTime presentFenceForPastVsync(Period minFramePeriod) const {
+ return target().presentFenceForPastVsync(minFramePeriod);
+ }
+
struct Frame {
Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
@@ -181,7 +185,7 @@
const auto fence = frame.end();
EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
- EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), fence);
+ EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, fence);
}
}
@@ -200,7 +204,7 @@
const auto fence = frame.end();
EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
- EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
+ EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
previousFence = fence;
}
@@ -222,7 +226,7 @@
const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
- EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);
+ EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
frameBeginTime += kPeriod;
previousFence = fence;
@@ -248,7 +252,7 @@
const auto fence = frame.end();
EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
- EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
+ EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
previousFence = fence;
}
@@ -274,7 +278,7 @@
const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
- EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);
+ EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
frameBeginTime += kPeriod;
previousFence = fence;
@@ -283,7 +287,7 @@
TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
constexpr Period kPeriod = (60_Hz).getPeriod();
- EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
+ EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, FenceTime::NO_FENCE);
EXPECT_FALSE(wouldPresentEarly(kPeriod));
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index fc54a8b..3df724a 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -34,6 +34,7 @@
#include "mock/MockSchedulerCallback.h"
#include <FrontEnd/LayerHierarchy.h>
+#include <scheduler/FrameTime.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include "FpsOps.h"
@@ -607,7 +608,8 @@
TimePoint::fromNs(2000)));
// Not crossing the min frame period
- vrrTracker->onFrameBegin(TimePoint::fromNs(2000), TimePoint::fromNs(1500));
+ vrrTracker->onFrameBegin(TimePoint::fromNs(2000),
+ {TimePoint::fromNs(1500), TimePoint::fromNs(1500)});
EXPECT_EQ(Fps::fromPeriodNsecs(1000),
scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(),
TimePoint::fromNs(2500)));
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 3b09554..b63f299 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <scheduler/FrameTime.h>
#include <scheduler/Timer.h>
#include "Scheduler/VSyncDispatchTimerQueue.h"
@@ -51,7 +52,7 @@
bool isVSyncInPhase(nsecs_t, Fps) final { return false; }
void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) final {}
void setRenderRate(Fps, bool) final {}
- void onFrameBegin(TimePoint, TimePoint) final {}
+ void onFrameBegin(TimePoint, scheduler::FrameTime) final {}
void onFrameMissed(TimePoint) final {}
void dump(std::string&) const final {}
bool isCurrentMode(const ftl::NonNull<DisplayModePtr>&) const final { return false; };
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index f36a8a6..8690dba 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -901,17 +901,20 @@
EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000));
- vrrTracker.onFrameBegin(TimePoint::fromNs(2000), TimePoint::fromNs(1500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(2000),
+ {TimePoint::fromNs(1500), TimePoint::fromNs(1500)});
EXPECT_EQ(3500, vrrTracker.nextAnticipatedVSyncTimeFrom(2000, 2000));
EXPECT_EQ(4500, vrrTracker.nextAnticipatedVSyncTimeFrom(3500, 3500));
// Miss when starting 4500 and expect the next vsync will be at 5000 (next one)
- vrrTracker.onFrameBegin(TimePoint::fromNs(3500), TimePoint::fromNs(2500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(3500),
+ {TimePoint::fromNs(2500), TimePoint::fromNs(2500)});
vrrTracker.onFrameMissed(TimePoint::fromNs(4500));
EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
- vrrTracker.onFrameBegin(TimePoint::fromNs(7000), TimePoint::fromNs(6500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(7000),
+ {TimePoint::fromNs(6500), TimePoint::fromNs(6500)});
EXPECT_EQ(10500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
}
@@ -943,7 +946,7 @@
// SF starts to catch up
EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2700));
- vrrTracker.onFrameBegin(TimePoint::fromNs(3000), TimePoint::fromNs(0));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(3000), {TimePoint::fromNs(0), TimePoint::fromNs(0)});
// SF misses last frame (3000) and observes that when committing (4000)
EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
@@ -952,17 +955,20 @@
// SF wakes up again instead of the (4000) missed frame
EXPECT_EQ(4500, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
- vrrTracker.onFrameBegin(TimePoint::fromNs(4500), TimePoint::fromNs(4500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(4500),
+ {TimePoint::fromNs(4500), TimePoint::fromNs(4500)});
// Timeline shifted. The app needs to get the next frame at (7500) as its last frame (6500) will
// be presented at (7500)
EXPECT_EQ(7500, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
EXPECT_EQ(5500, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
- vrrTracker.onFrameBegin(TimePoint::fromNs(5500), TimePoint::fromNs(4500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(5500),
+ {TimePoint::fromNs(4500), TimePoint::fromNs(4500)});
EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(7500, 7500));
EXPECT_EQ(6500, vrrTracker.nextAnticipatedVSyncTimeFrom(5500, 5500));
- vrrTracker.onFrameBegin(TimePoint::fromNs(6500), TimePoint::fromNs(5500));
+ vrrTracker.onFrameBegin(TimePoint::fromNs(6500),
+ {TimePoint::fromNs(5500), TimePoint::fromNs(5500)});
}
TEST_F(VSyncPredictorTest, renderRateIsPreservedForCommittedVsyncs) {
@@ -1020,6 +1026,35 @@
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(9001), Eq(13000));
}
+TEST_F(VSyncPredictorTest, timelineNotAdjustedForEarlyPresent) {
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ const int32_t kGroup = 0;
+ const auto kResolution = ui::Size(1920, 1080);
+ const auto refreshRate = Fps::fromPeriodNsecs(500);
+ const auto minFrameRate = Fps::fromPeriodNsecs(1000);
+ hal::VrrConfig vrrConfig;
+ vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
+ const ftl::NonNull<DisplayModePtr> kMode =
+ ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), refreshRate, kGroup,
+ kResolution, DEFAULT_DISPLAY_ID)
+ .setVrrConfig(std::move(vrrConfig))
+ .build());
+
+ VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
+ kMinimumSamplesForPrediction, kOutlierTolerancePercent};
+
+ vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
+ vrrTracker.addVsyncTimestamp(0);
+ EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
+
+ constexpr auto kLastConfirmedExpectedPresentTime = TimePoint::fromNs(1000);
+ constexpr auto kLastActualSignalTime = TimePoint::fromNs(700); // presented early
+ vrrTracker.onFrameBegin(TimePoint::fromNs(1400),
+ {kLastActualSignalTime, kLastConfirmedExpectedPresentTime});
+ EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1400, 1000));
+ EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2000, 1000));
+}
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
index 4f44d1b..8d6d1d3 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
@@ -18,6 +18,8 @@
#include <gmock/gmock.h>
+#include <scheduler/FrameTime.h>
+
#include "Scheduler/VSyncTracker.h"
namespace android::mock {
@@ -37,7 +39,7 @@
MOCK_METHOD(bool, isVSyncInPhase, (nsecs_t, Fps), (override));
MOCK_METHOD(void, setDisplayModePtr, (ftl::NonNull<DisplayModePtr>), (override));
MOCK_METHOD(void, setRenderRate, (Fps, bool), (override));
- MOCK_METHOD(void, onFrameBegin, (TimePoint, TimePoint), (override));
+ MOCK_METHOD(void, onFrameBegin, (TimePoint, scheduler::FrameTime), (override));
MOCK_METHOD(void, onFrameMissed, (TimePoint), (override));
MOCK_METHOD(void, dump, (std::string&), (const, override));
MOCK_METHOD(bool, isCurrentMode, (const ftl::NonNull<DisplayModePtr>&), (const, override));