Merge "[Shadows] Add shadow vertex generation code and shaders [8/n]"
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index abdf168..5597bcd 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -364,7 +364,7 @@
}
if (err != OK) {
- aerr << "Error dumping service info status_t: (" << err << ") "
+ aerr << "Error dumping service info status_t: " << statusToString(err) << " "
<< serviceName << endl;
}
});
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 83ebeca..bf487c4 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -280,6 +280,20 @@
return begin() == region.begin();
}
+bool Region::hasSameRects(const Region& other) const {
+ size_t thisRectCount = 0;
+ android::Rect const* thisRects = getArray(&thisRectCount);
+ size_t otherRectCount = 0;
+ android::Rect const* otherRects = other.getArray(&otherRectCount);
+
+ if (thisRectCount != otherRectCount) return false;
+
+ for (size_t i = 0; i < thisRectCount; i++) {
+ if (thisRects[i] != otherRects[i]) return false;
+ }
+ return true;
+}
+
// ----------------------------------------------------------------------------
void Region::addRectUnchecked(int l, int t, int r, int b)
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 85abb38..06b6bfe 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -49,6 +49,15 @@
return isZero(fabs(f) - 1.0f);
}
+bool Transform::operator==(const Transform& other) const {
+ return mMatrix[0][0] == other.mMatrix[0][0] && mMatrix[0][1] == other.mMatrix[0][1] &&
+ mMatrix[0][2] == other.mMatrix[0][2] && mMatrix[1][0] == other.mMatrix[1][0] &&
+ mMatrix[1][1] == other.mMatrix[1][1] && mMatrix[1][2] == other.mMatrix[1][2] &&
+ mMatrix[2][0] == other.mMatrix[2][0] && mMatrix[2][1] == other.mMatrix[2][1] &&
+ mMatrix[2][2] == other.mMatrix[2][2];
+ ;
+}
+
Transform Transform::operator * (const Transform& rhs) const
{
if (CC_LIKELY(mType == IDENTITY))
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 4cd9a0b..bec2552 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -16,6 +16,8 @@
#pragma once
+#include <ostream>
+
namespace android {
class FloatRect {
@@ -52,4 +54,9 @@
return a.left == b.left && a.top == b.top && a.right == b.right && a.bottom == b.bottom;
}
+static inline void PrintTo(const FloatRect& rect, ::std::ostream* os) {
+ *os << "FloatRect(" << rect.left << ", " << rect.top << ", " << rect.right << ", "
+ << rect.bottom << ")";
+}
+
} // namespace android
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 1768805..2f2229e 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_UI_RECT
#define ANDROID_UI_RECT
+#include <ostream>
+
#include <utils/Flattenable.h>
#include <utils/Log.h>
#include <utils/TypeHelpers.h>
@@ -214,6 +216,12 @@
}
};
+// Defining PrintTo helps with Google Tests.
+static inline void PrintTo(const Rect& rect, ::std::ostream* os) {
+ *os << "Rect(" << rect.left << ", " << rect.top << ", " << rect.right << ", " << rect.bottom
+ << ")";
+}
+
ANDROID_BASIC_TYPES_TRAITS(Rect)
}; // namespace android
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 79642ae..2db3b10 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <ostream>
#include <utils/Vector.h>
@@ -119,6 +120,8 @@
// returns true if the regions share the same underlying storage
bool isTriviallyEqual(const Region& region) const;
+ // returns true if the regions consist of the same rectangle sequence
+ bool hasSameRects(const Region& region) const;
/* various ways to access the rectangle list */
@@ -213,6 +216,21 @@
Region& Region::operator += (const Point& pt) {
return translateSelf(pt.x, pt.y);
}
+
+// Defining PrintTo helps with Google Tests.
+static inline void PrintTo(const Region& region, ::std::ostream* os) {
+ Region::const_iterator head = region.begin();
+ Region::const_iterator const tail = region.end();
+ bool first = true;
+ while (head != tail) {
+ *os << (first ? "Region(" : ", ");
+ PrintTo(*head, os);
+ head++;
+ first = false;
+ }
+ *os << ")";
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index fab2d9e..de07684 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <ostream>
#include <string>
#include <hardware/hardware.h>
@@ -63,6 +64,7 @@
bool preserveRects() const;
uint32_t getType() const;
uint32_t getOrientation() const;
+ bool operator==(const Transform& other) const;
const vec3& operator [] (size_t i) const; // returns column i
float tx() const;
@@ -115,6 +117,12 @@
mutable uint32_t mType;
};
+static inline void PrintTo(const Transform& t, ::std::ostream* os) {
+ std::string out;
+ t.dump(out, "ui::Transform");
+ *os << out;
+}
+
} // namespace ui
} // namespace android
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 7c061c5..ae9a348 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -82,7 +82,7 @@
// Check if the "deep touch" feature is on.
static bool deepPressEnabled() {
std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
- INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "false");
+ INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
if (flag_value == "1" || flag_value == "true") {
ALOGI("Deep press feature enabled.");
diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
deleted file mode 100644
index 6741cc9..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2019 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 <string>
-
-#include <android-base/stringprintf.h>
-#include <gmock/gmock.h>
-
-namespace {
-
-using android::base::StringAppendF;
-using FloatRect = android::FloatRect;
-
-void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) {
- StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom);
-}
-
-// Checks for a region match
-MATCHER_P(FloatRectEq, expected, "") {
- std::string buf;
- buf.append("FloatRects are not equal\n");
- dumpFloatRect(expected, buf, "expected rect");
- dumpFloatRect(arg, buf, "actual rect");
- *result_listener << buf;
-
- const float TOLERANCE = 1e-3f;
- return (std::fabs(expected.left - arg.left) < TOLERANCE) &&
- (std::fabs(expected.top - arg.top) < TOLERANCE) &&
- (std::fabs(expected.right - arg.right) < TOLERANCE) &&
- (std::fabs(expected.bottom - arg.bottom) < TOLERANCE);
-}
-
-} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 88acd04..2e030a1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -23,10 +23,8 @@
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
-#include "FloatRectMatcher.h"
#include "MockHWC2.h"
#include "MockHWComposer.h"
-#include "RectMatcher.h"
#include "RegionMatcher.h"
namespace android::compositionengine {
@@ -159,19 +157,19 @@
mLayerFEState.geomUsesSourceCrop = false;
const FloatRect expected{};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) {
const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) {
mLayerFEState.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) {
@@ -179,7 +177,7 @@
mLayerFEState.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
const FloatRect expected{0.f, 0.f, 1080.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) {
@@ -218,7 +216,7 @@
mLayerFEState.geomBufferTransform = entry.buffer;
mOutputState.orientation = entry.display;
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i;
+ EXPECT_THAT(calculateOutputSourceCrop(), entry.expected) << "entry " << i;
}
}
@@ -226,14 +224,14 @@
mLayerFEState.geomContentCrop = Rect{0, 0, 960, 540};
const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
mOutputState.viewport = Rect{0, 0, 960, 540};
const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+ EXPECT_THAT(calculateOutputSourceCrop(), expected);
}
/*
@@ -265,50 +263,50 @@
TEST_F(OutputLayerDisplayFrameTest, correctForSimpleDefaultCase) {
const Rect expected{0, 0, 1920, 1080};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame) {
mLayerFEState.transparentRegionHint = Region{Rect{0, 0, 1920, 1080}};
const Rect expected{0, 0, 0, 0};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrame) {
mLayerFEState.geomCrop = Rect{100, 200, 300, 500};
const Rect expected{100, 200, 300, 500};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrameRotated) {
mLayerFEState.geomCrop = Rect{100, 200, 300, 500};
mLayerFEState.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
const Rect expected{1420, 100, 1720, 300};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) {
mLayerFEState.geomCrop = Rect{};
const Rect expected{0, 0, 1920, 1080};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) {
mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
const Rect expected{0, 0, 960, 540};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, viewportAffectsFrame) {
mOutputState.viewport = Rect{0, 0, 960, 540};
const Rect expected{0, 0, 960, 540};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
TEST_F(OutputLayerDisplayFrameTest, outputTransformAffectsDisplayFrame) {
mOutputState.transform = ui::Transform{HAL_TRANSFORM_ROT_90};
const Rect expected{-1080, 0, 0, 1920};
- EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+ EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 37b62d8..08b8818 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -35,7 +35,6 @@
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
-#include "TransformMatcher.h"
namespace android::compositionengine {
namespace {
@@ -244,7 +243,7 @@
mOutput->setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
- EXPECT_THAT(mOutput->getState().transform, TransformEq(transform));
+ EXPECT_THAT(mOutput->getState().transform, transform);
EXPECT_EQ(orientation, mOutput->getState().orientation);
EXPECT_EQ(frame, mOutput->getState().frame);
EXPECT_EQ(viewport, mOutput->getState().viewport);
diff --git a/services/surfaceflinger/CompositionEngine/tests/RectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/RectMatcher.h
deleted file mode 100644
index d4c76bc..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/RectMatcher.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <string>
-
-#include <android-base/stringprintf.h>
-#include <gmock/gmock.h>
-
-namespace {
-
-using android::base::StringAppendF;
-using Rect = android::Rect;
-
-void dumpRect(const Rect& rect, std::string& result, const char* name) {
- StringAppendF(&result, "%s (%d %d %d %d) ", name, rect.left, rect.top, rect.right, rect.bottom);
-}
-
-// Checks for a region match
-MATCHER_P(RectEq, expected, "") {
- std::string buf;
- buf.append("Rects are not equal\n");
- dumpRect(expected, buf, "expected rect");
- dumpRect(arg, buf, "actual rect");
- *result_listener << buf;
-
- return (expected.left == arg.left) && (expected.top == arg.top) &&
- (expected.right == arg.right) && (expected.bottom == arg.bottom);
-}
-
-} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
index 5a4efa9..2adde23 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
+++ b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
@@ -20,24 +20,22 @@
namespace {
-// Checks for a region match
-MATCHER_P(RegionEq, expected, "") {
- std::string buf;
- buf.append("Regions are not equal\n");
- expected.dump(buf, "expected region");
- arg.dump(buf, "actual region");
- *result_listener << buf;
+using Region = android::Region;
- size_t expectedRectCount = 0;
- android::Rect const* expectedRects = expected.getArray(&expectedRectCount);
- size_t actualRectCount = 0;
- android::Rect const* actualRects = arg.getArray(&actualRectCount);
+struct RegionMatcher : public testing::MatcherInterface<const Region&> {
+ const Region expected;
- if (expectedRectCount != actualRectCount) return false;
- for (size_t i = 0; i < expectedRectCount; i++) {
- if (expectedRects[i] != actualRects[i]) return false;
+ explicit RegionMatcher(const Region& expectedValue) : expected(expectedValue) {}
+
+ bool MatchAndExplain(const Region& actual, testing::MatchResultListener*) const override {
+ return expected.hasSameRects(actual);
}
- return true;
+
+ void DescribeTo(::std::ostream* os) const override { PrintTo(expected, os); }
+};
+
+testing::Matcher<const Region&> RegionEq(const Region& expected) {
+ return MakeMatcher(new RegionMatcher(expected));
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
deleted file mode 100644
index ea07bed..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2019 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 <string>
-
-#include <gmock/gmock.h>
-
-namespace {
-
-// Check for a transform match
-MATCHER_P(TransformEq, expected, "") {
- std::string buf;
- buf.append("Transforms are not equal\n");
- expected.dump(buf, "expected transform");
- arg.dump(buf, "actual transform");
- *result_listener << buf;
-
- const float TOLERANCE = 1e-3f;
-
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- if (std::fabs(expected[i][j] - arg[i][j]) > TOLERANCE) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-} // namespace
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d480f7c..d8dad0b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -247,8 +247,8 @@
// the refresh period and whatever closest timestamp we have.
std::lock_guard lock(displayData.lastHwVsyncLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
- auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod();
- return now - ((now - displayData.lastHwVsync) % vsyncPeriod);
+ auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId);
+ return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos);
}
bool HWComposer::isConnected(DisplayId displayId) const {
@@ -291,6 +291,23 @@
return config;
}
+// Composer 2.4
+
+bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
+ return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
+}
+
+nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
+ nsecs_t vsyncPeriodNanos;
+ auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
+ if (error != HWC2::Error::None) {
+ LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
+ return 0;
+ }
+
+ return vsyncPeriodNanos;
+}
+
int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, -1);
@@ -541,7 +558,9 @@
return NO_ERROR;
}
-status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
+status_t HWComposer::setActiveConfigWithConstraints(
+ DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints,
+ HWC2::VsyncPeriodChangeTimeline* outTimeline) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -550,7 +569,9 @@
return BAD_INDEX;
}
- auto error = displayData.hwcDisplay->setActiveConfig(displayData.configMap[configId]);
+ auto error =
+ displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId],
+ constraints, outTimeline);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index e87c5c3..077e452 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -102,9 +102,6 @@
// set power mode
virtual status_t setPowerMode(DisplayId displayId, int mode) = 0;
- // set active config
- virtual status_t setActiveConfig(DisplayId displayId, size_t configId) = 0;
-
// Sets a color transform to be applied to the result of composition
virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0;
@@ -180,6 +177,14 @@
virtual bool isUsingVrComposer() const = 0;
+ // Composer 2.4
+ virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
+ virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
+ virtual status_t setActiveConfigWithConstraints(
+ DisplayId displayId, size_t configId,
+ const HWC2::VsyncPeriodChangeConstraints& constraints,
+ HWC2::VsyncPeriodChangeTimeline* outTimeline) = 0;
+
// for debugging ----------------------------------------------------------
virtual void dump(std::string& out) const = 0;
@@ -232,9 +237,6 @@
// set power mode
status_t setPowerMode(DisplayId displayId, int mode) override;
- // set active config
- status_t setActiveConfig(DisplayId displayId, size_t configId) override;
-
// Sets a color transform to be applied to the result of composition
status_t setColorTransform(DisplayId displayId, const mat4& transform) override;
@@ -305,6 +307,13 @@
bool isUsingVrComposer() const override;
+ // Composer 2.4
+ bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
+ nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
+ status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
+ const HWC2::VsyncPeriodChangeConstraints& constraints,
+ HWC2::VsyncPeriodChangeTimeline* outTimeline) override;
+
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 1d50fe1..71a6a2f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -59,11 +59,13 @@
namespace android {
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
- const scheduler::RefreshRateConfigs& refreshRateConfig)
+ const scheduler::RefreshRateConfigs& refreshRateConfig,
+ ISchedulerCallback& schedulerCallback)
: mPrimaryDispSync(new impl::DispSync("SchedulerDispSync",
sysprop::running_without_sync_framework(true))),
mEventControlThread(new impl::EventControlThread(std::move(function))),
mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
+ mSchedulerCallback(schedulerCallback),
mRefreshRateConfigs(refreshRateConfig) {
using namespace sysprop;
@@ -104,10 +106,12 @@
Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
- const scheduler::RefreshRateConfigs& configs)
+ const scheduler::RefreshRateConfigs& configs,
+ ISchedulerCallback& schedulerCallback)
: mPrimaryDispSync(std::move(primaryDispSync)),
mEventControlThread(std::move(eventControlThread)),
mSupportKernelTimer(false),
+ mSchedulerCallback(schedulerCallback),
mRefreshRateConfigs(configs) {}
Scheduler::~Scheduler() {
@@ -368,12 +372,7 @@
mFeatures.configId = newConfigId;
};
auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
- changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
-}
-
-void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mSchedulerCallback = callback;
+ mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
}
void Scheduler::resetIdleTimer() {
@@ -486,7 +485,7 @@
}
}
const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
- changeRefreshRate(newRefreshRate, event);
+ mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
}
HwcConfigIndexType Scheduler::calculateRefreshRateType() {
@@ -526,10 +525,36 @@
return mFeatures.configId;
}
-void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mSchedulerCallback) {
- mSchedulerCallback->changeRefreshRate(refreshRate, configEvent);
+void Scheduler::onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline) {
+ if (timeline.refreshRequired) {
+ mSchedulerCallback.repaintEverythingForHWC();
+ }
+
+ std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
+ mLastVsyncPeriodChangeTimeline = std::make_optional(timeline);
+
+ const auto maxAppliedTime = systemTime() + MAX_VSYNC_APPLIED_TIME.count();
+ if (timeline.newVsyncAppliedTimeNanos > maxAppliedTime) {
+ mLastVsyncPeriodChangeTimeline->newVsyncAppliedTimeNanos = maxAppliedTime;
+ }
+}
+
+void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
+ bool callRepaint = false;
+ {
+ std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
+ if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
+ if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) {
+ mLastVsyncPeriodChangeTimeline->refreshRequired = false;
+ } else {
+ // We need to send another refresh as refreshTimeNanos is still in the future
+ callRepaint = true;
+ }
+ }
+ }
+
+ if (callRepaint) {
+ mSchedulerCallback.repaintEverythingForHWC();
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 04a8390..15277ce 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -41,22 +41,24 @@
class InjectVSyncSource;
struct DisplayStateInfo;
+class ISchedulerCallback {
+public:
+ virtual ~ISchedulerCallback() = default;
+ virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
+ scheduler::RefreshRateConfigEvent) = 0;
+ virtual void repaintEverythingForHWC() = 0;
+};
+
class Scheduler {
public:
using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
using ConfigEvent = scheduler::RefreshRateConfigEvent;
- class ISchedulerCallback {
- public:
- virtual ~ISchedulerCallback() = default;
- virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0;
- };
-
// Indicates whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
- const scheduler::RefreshRateConfigs&);
+ const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);
virtual ~Scheduler();
@@ -114,9 +116,6 @@
// Detects content using layer history, and selects a matching refresh rate.
void chooseRefreshRateForContent();
- // Called by Scheduler to control SurfaceFlinger operations.
- void setSchedulerCallback(ISchedulerCallback*);
-
bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
@@ -131,6 +130,12 @@
// Get the appropriate refresh for current conditions.
std::optional<HwcConfigIndexType> getPreferredConfigId();
+ // Notifies the scheduler about a refresh rate timeline change.
+ void onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline);
+
+ // Notifies the scheduler when the display was refreshed
+ void onDisplayRefreshed(nsecs_t timestamp);
+
private:
friend class TestableScheduler;
@@ -142,7 +147,7 @@
// Used by tests to inject mocks.
Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
- const scheduler::RefreshRateConfigs&);
+ const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);
std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs,
nsecs_t offsetThresholdForNextVsync);
@@ -165,8 +170,6 @@
void setVsyncPeriod(nsecs_t period);
HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
- // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters.
- void changeRefreshRate(const RefreshRate&, ConfigEvent);
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
@@ -203,8 +206,7 @@
// Timer used to monitor display power mode.
std::optional<scheduler::OneShotTimer> mDisplayPowerTimer;
- std::mutex mCallbackLock;
- ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr;
+ ISchedulerCallback& mSchedulerCallback;
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
@@ -223,6 +225,11 @@
} mFeatures GUARDED_BY(mFeatureStateLock);
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
+
+ std::mutex mVsyncTimelineLock;
+ std::optional<HWC2::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
+ GUARDED_BY(mVsyncTimelineLock);
+ static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 2394ed2..fb4f315 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -85,7 +85,7 @@
};
if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
- ALOGW("Failed to set timerfd");
+ ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
}
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3894992..3b99a58 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -23,6 +23,7 @@
#include <utils/Trace.h>
#include <algorithm>
#include <chrono>
+#include <sstream>
#include "SchedulerUtils.h"
namespace android::scheduler {
@@ -153,12 +154,24 @@
}
auto const oldest = *std::min_element(timestamps.begin(), timestamps.end());
- auto const ordinalRequest = (timePoint - oldest + slope) / slope;
+
+ // See b/145667109, the ordinal calculation must take into account the intercept.
+ auto const zeroPoint = oldest + intercept;
+ auto const ordinalRequest = (timePoint - zeroPoint + slope) / slope;
auto const prediction = (ordinalRequest * slope) + intercept + oldest;
- ALOGV("prediction made from: %" PRId64 " prediction: %" PRId64 " (+%" PRId64 ") slope: %" PRId64
- " intercept: %" PRId64,
- timePoint, prediction, prediction - timePoint, slope, intercept);
+ auto const printer = [&, slope = slope, intercept = intercept] {
+ std::stringstream str;
+ str << "prediction made from: " << timePoint << "prediction: " << prediction << " (+"
+ << prediction - timePoint << ") slope: " << slope << " intercept: " << intercept
+ << "oldestTS: " << oldest << " ordinal: " << ordinalRequest;
+ return str.str();
+ };
+
+ ALOGV("%s", printer().c_str());
+ LOG_ALWAYS_FATAL_IF(prediction < timePoint, "VSyncPredictor: model miscalculation: %s",
+ printer().c_str());
+
return prediction;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9f4dd2b..8e94529 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1004,11 +1004,25 @@
LOG_ALWAYS_FATAL_IF(!displayId);
ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps);
- getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value());
- // we need to submit an empty frame to HWC to start the process
+ // TODO(b/142753666) use constrains
+ HWC2::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+
+ HWC2::VsyncPeriodChangeTimeline outTimeline;
+ auto status =
+ getHwComposer().setActiveConfigWithConstraints(*displayId,
+ mUpcomingActiveConfig.configId.value(),
+ constraints, &outTimeline);
+ if (status != NO_ERROR) {
+ LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status);
+ return false;
+ }
+
+ mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
+ // Scheduler will submit an empty frame to HWC if needed.
mCheckPendingFence = true;
- mEventQueue->invalidate();
return false;
}
@@ -1361,8 +1375,7 @@
return 0;
}
- const auto config = getHwComposer().getActiveConfig(*displayId);
- return config ? config->getVsyncPeriod() : 0;
+ return getHwComposer().getDisplayVsyncPeriod(*displayId);
}
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1448,9 +1461,13 @@
}
void SurfaceFlinger::onVsyncPeriodTimingChangedReceived(
- int32_t /*sequenceId*/, hwc2_display_t /*display*/,
- const hwc_vsync_period_change_timeline_t& /*updatedTimeline*/) {
- // TODO(b/142753004): use timeline when changing refresh rate
+ int32_t sequenceId, hwc2_display_t /*display*/,
+ const hwc_vsync_period_change_timeline_t& updatedTimeline) {
+ Mutex::Autolock lock(mStateLock);
+ if (sequenceId != getBE().mComposerSequenceId) {
+ return;
+ }
+ mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline);
}
void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
@@ -1761,11 +1778,17 @@
mGeometryInvalid = false;
+ // Store the present time just before calling to the composition engine so we could notify
+ // the scheduler.
+ const auto presentTime = systemTime();
+
mCompositionEngine->present(refreshArgs);
mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
// Reset the frame start time now that we've recorded this frame.
mFrameStartTime = 0;
+ mScheduler->onDisplayRefreshed(presentTime);
+
postFrame();
postComposition();
@@ -2551,7 +2574,7 @@
// start the EventThread
mScheduler =
getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
- *mRefreshRateConfigs);
+ *mRefreshRateConfigs, *this);
mAppConnectionHandle =
mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
mPhaseOffsets->getOffsetThresholdForNextVsync(),
@@ -2570,8 +2593,6 @@
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
RegionSamplingThread::EnvironmentTimingTunables());
-
- mScheduler->setSchedulerCallback(this);
}
void SurfaceFlinger::commitTransaction()
@@ -4316,8 +4337,8 @@
" refresh-rate : %f fps\n"
" x-dpi : %f\n"
" y-dpi : %f\n",
- 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
- activeConfig->getDpiY());
+ 1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId),
+ activeConfig->getDpiX(), activeConfig->getDpiY());
}
StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0);
@@ -5438,6 +5459,27 @@
void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
const std::vector<int32_t>& allowedConfigs) {
if (!display->isPrimary()) {
+ // TODO(b/144711714): For non-primary displays we should be able to set an active config
+ // as well. For now, just call directly to setActiveConfigWithConstraints but ideally
+ // it should go thru setDesiredActiveConfig, similar to primary display.
+ ALOGV("setAllowedDisplayConfigsInternal for non-primary display");
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ HWC2::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+
+ HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
+ getHwComposer().setActiveConfigWithConstraints(*displayId, allowedConfigs[0], constraints,
+ &timeline);
+ if (timeline.refreshRequired) {
+ repaintEverythingForHWC();
+ }
+
+ auto configId = HwcConfigIndexType(allowedConfigs[0]);
+ display->setActiveConfig(configId);
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
return;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ae3f2d7..53b8908 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -176,7 +176,7 @@
public ClientCache::ErasedRecipient,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
- private Scheduler::ISchedulerCallback {
+ private ISchedulerCallback {
public:
SurfaceFlingerBE& getBE() { return mBE; }
const SurfaceFlingerBE& getBE() const { return mBE; }
@@ -273,9 +273,6 @@
// force full composition on all displays
void repaintEverything();
- // force full composition on all displays without resetting the scheduler idle timer.
- void repaintEverythingForHWC();
-
surfaceflinger::Factory& getFactory() { return mFactory; }
// The CompositionEngine encapsulates all composition related interfaces and actions.
@@ -519,9 +516,11 @@
const hwc_vsync_period_change_timeline_t& updatedTimeline) override;
/* ------------------------------------------------------------------------
- * Scheduler::ISchedulerCallback
+ * ISchedulerCallback
*/
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override;
+ // force full composition on all displays without resetting the scheduler idle timer.
+ void repaintEverythingForHWC() override;
/* ------------------------------------------------------------------------
* Message handling
*/
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 4f439da..bd4cdba 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -64,8 +64,9 @@
}
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
- SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs) {
- return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
+ SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs,
+ ISchedulerCallback& schedulerCallback) {
+ return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs, schedulerCallback);
}
std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 42bb177..1a24448 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -32,7 +32,8 @@
std::unique_ptr<MessageQueue> createMessageQueue() override;
std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override;
std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
- const scheduler::RefreshRateConfigs&) override;
+ const scheduler::RefreshRateConfigs&,
+ ISchedulerCallback&) override;
std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 20784d2..0db941d 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -40,6 +40,7 @@
class HWComposer;
class IGraphicBufferConsumer;
class IGraphicBufferProducer;
+class ISchedulerCallback;
class Layer;
class MessageQueue;
class Scheduler;
@@ -75,7 +76,8 @@
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
virtual std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
- const scheduler::RefreshRateConfigs&) = 0;
+ const scheduler::RefreshRateConfigs&,
+ ISchedulerCallback&) = 0;
virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 40c00c4..fa095aa 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -26,17 +26,17 @@
namespace android {
-class TestableScheduler : public Scheduler {
+class TestableScheduler : public Scheduler, private ISchedulerCallback {
public:
explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs)
- : Scheduler([](bool) {}, configs) {
+ : Scheduler([](bool) {}, configs, *this) {
mLayerHistory.emplace();
}
TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
const scheduler::RefreshRateConfigs& configs)
- : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {
+ : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this) {
mLayerHistory.emplace();
}
@@ -68,6 +68,10 @@
mutablePrimaryDispSync().reset();
mConnections.clear();
}
+
+private:
+ void changeRefreshRate(const RefreshRate&, ConfigEvent) override {}
+ void repaintEverythingForHWC() override {}
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b2210ec..facf142 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -84,7 +84,8 @@
}
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
- const scheduler::RefreshRateConfigs&) override {
+ const scheduler::RefreshRateConfigs&,
+ ISchedulerCallback&) override {
return nullptr;
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index d0c8090..4cb6a38 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -319,4 +319,36 @@
}
}
+// See b/145667109, and comment in prod code under test.
+TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 158929578733000,
+ 158929306806205, // oldest TS in ringbuffer
+ 158929650879052,
+ 158929661969209,
+ 158929684198847,
+ 158929695268171,
+ 158929706370359,
+ };
+ auto const idealPeriod = 11111111;
+ auto const expectedPeriod = 11113500;
+ auto const expectedIntercept = -395335;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+
+ // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
+ // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
+ // so failure to account for the offset will floor the ordinal to 38, which was in the past.
+ auto const timePoint = 158929728723871;
+ auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
+ EXPECT_THAT(prediction, Ge(timePoint));
+}
+
} // namespace android::scheduler