Merge "Account for release callbacks when determing if sync is finished" into tm-qpr-dev
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 32ffe14..5267b02 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -294,12 +294,9 @@
write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
-# Set up histogram triggers
- # rss_stat_throttled (bucket size == 512KB)
- chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+ # allow creating event triggers
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
- write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
- write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47d801a..9358e29 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -897,6 +897,10 @@
mApplyToken = nullptr;
}
+uint64_t SurfaceComposerClient::Transaction::getId() {
+ return mId;
+}
+
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index efbdb36..b598b43 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -461,6 +461,10 @@
// Clears the contents of the transaction without applying it.
void clear();
+ // Returns the current id of the transaction.
+ // The id is updated every time the transaction is applied.
+ uint64_t getId();
+
status_t apply(bool synchronous = false, bool oneWay = false);
// Merge another transaction in to this one, clearing other
// as if it had been applied.
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 262987f..c6cdeb7 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -566,6 +566,55 @@
bgSurface->expectTap(12, 24);
}
+TEST_F(InputSurfacesTest, touchable_region) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31});
+
+ surface->showAt(11, 22);
+
+ // A tap within the surface but outside the touchable region should not be sent to the surface.
+ injectTap(20, 30);
+ EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+
+ injectTap(31, 52);
+ surface->expectTap(20, 30);
+}
+
+TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ // Set the touchable region to the values at the limit of its corresponding type.
+ // Since the surface is offset from the origin, the touchable region will be transformed into
+ // display space, which would trigger an overflow or an underflow. Ensure that we are protected
+ // against such a situation.
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+
+ fgSurface->showAt(100, 100);
+
+ // Expect no crash for overflow. The overflowed touchable region is ignored, so the background
+ // surface receives touch.
+ injectTap(112, 124);
+ bgSurface->expectTap(12, 24);
+}
+
+TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(0, 0);
+
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+ fgSurface->showAt(0, 0);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // Expect no crash for overflow.
+ injectTap(12, 24);
+ fgSurface->expectTap(6, 12);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/libs/shaders/TEST_MAPPING b/libs/shaders/TEST_MAPPING
new file mode 100644
index 0000000..ad6514d
--- /dev/null
+++ b/libs/shaders/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "librenderengine_test"
+ },
+ {
+ "name": "libshaders_test"
+ }
+ ]
+}
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 62745dc..f80e93f 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -469,12 +469,17 @@
float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
std::vector<tonemap::ShaderUniform> uniforms;
- if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
+
+ const ui::Dataspace inputDataspace = linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
+ ? linearEffect.inputDataspace
+ : linearEffect.fakeInputDataspace;
+
+ if (inputDataspace == linearEffect.outputDataspace) {
uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
uniforms.push_back(
{.name = "in_xyzToRgb", .value = buildUniformValue<mat4>(colorTransform)});
} else {
- ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+ ColorSpace inputColorSpace = toColorSpace(inputDataspace);
ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
uniforms.push_back({.name = "in_rgbToXyz",
.value = buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ()))});
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
new file mode 100644
index 0000000..cf671bc
--- /dev/null
+++ b/libs/shaders/tests/Android.bp
@@ -0,0 +1,48 @@
+// Copyright 2022 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libshaders_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "shaders_test.cpp",
+ ],
+ header_libs: [
+ "libtonemap_headers",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.composer3-V1-ndk",
+ "android.hardware.graphics.common@1.2",
+ "libnativewindow",
+ ],
+ static_libs: [
+ "libarect",
+ "libgmock",
+ "libgtest",
+ "libmath",
+ "libshaders",
+ "libtonemap",
+ "libui-types",
+ ],
+}
diff --git a/libs/shaders/tests/shaders_test.cpp b/libs/shaders/tests/shaders_test.cpp
new file mode 100644
index 0000000..d45fb24
--- /dev/null
+++ b/libs/shaders/tests/shaders_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "shaders/shaders.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <math/mat4.h>
+#include <tonemap/tonemap.h>
+#include <ui/ColorSpace.h>
+#include <cmath>
+
+namespace android {
+
+using testing::Contains;
+using testing::HasSubstr;
+
+struct ShadersTest : public ::testing::Test {};
+
+namespace {
+
+MATCHER_P2(UniformEq, name, value, "") {
+ return arg.name == name && arg.value == value;
+}
+
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+ std::vector<uint8_t> result;
+ result.resize(sizeof(value));
+ std::memcpy(result.data(), &value, sizeof(value));
+ return result;
+}
+
+} // namespace
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsNoOpGamutMatrices) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+ mat4 colorTransform = mat4::scale(vec4(.9, .9, .9, 1.));
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, colorTransform, 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(colorTransform))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsGamutTransformMatrices) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+ .outputDataspace = ui::Dataspace::DISPLAY_P3,
+ .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+ ColorSpace inputColorSpace = ColorSpace::sRGB();
+ ColorSpace outputColorSpace = ColorSpace::DisplayP3();
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_rgbToXyz",
+ buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ())))));
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_xyzToRgb",
+ buildUniformValue<mat4>(mat4(outputColorSpace.getXYZtoRGB())))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_respectsFakeInputDataspace) {
+ shaders::LinearEffect effect =
+ shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+ .outputDataspace = ui::Dataspace::DISPLAY_P3,
+ .fakeInputDataspace = ui::Dataspace::DISPLAY_P3};
+
+ auto uniforms =
+ shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+ aidl::android::hardware::graphics::composer3::
+ RenderIntent::COLORIMETRIC);
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+ EXPECT_THAT(uniforms, Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(mat4()))));
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
index 57338f4..2affb60 100644
--- a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
+++ b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
@@ -49,6 +49,8 @@
// negative duration.
uint32_t error_count;
+ // Needed to make 32-bit arch struct size match 64-bit BPF arch struct size.
+ uint32_t padding0;
} UidTrackingInfo;
typedef struct {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f8c53c3..d9c89cd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -358,8 +358,6 @@
// composition.
if (!mBufferInfo.mFrameLatencyNeeded) return;
- mAlreadyDisplayedThisCompose = false;
-
// Update mFrameEventHistory.
finalizeFrameEventHistory(glDoneFence, compositorTiming);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1a5b925..fecf5ae 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -79,10 +79,10 @@
// For example we can only use it if all the displays are client comp, and we need
// to merge all the client comp fences. We could do this, but for now we just
// disable the optimization when a layer is composed on multiple displays.
- if (mAlreadyDisplayedThisCompose) {
+ if (mClearClientCompositionFenceOnLayerDisplayed) {
mLastClientCompositionFence = nullptr;
} else {
- mAlreadyDisplayedThisCompose = true;
+ mClearClientCompositionFenceOnLayerDisplayed = true;
}
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2e7a377..e65aa73 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -147,6 +147,8 @@
bool hasProtectedLayers() const;
+ bool hasSolidColorLayers() const;
+
private:
CachedSet() = default;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 29d3366..5aec7c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -248,6 +248,12 @@
bool isProtected() const {
return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
}
+
+ bool hasSolidColorCompositionType() const {
+ return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
+ aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
+ }
+
float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
void dump(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index cccf907..ea856e4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -261,7 +261,7 @@
}
if (isPowerHintSessionEnabled()) {
- mPowerAdvisor->setValidateTiming(mId, startTime, systemTime());
+ mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
}
@@ -371,7 +371,7 @@
if (!getCompositionEngine().getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
- mPowerAdvisor->setPresentDelayedTime(mId, getState().earliestPresentTime);
+ mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime);
}
}
@@ -379,7 +379,7 @@
getState().previousPresentFence);
if (isPowerHintSessionEnabled()) {
- mPowerAdvisor->setPresentTiming(mId, startTime, systemTime());
+ mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime());
}
fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index d4727ca..070b285 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1304,6 +1304,7 @@
const auto& layerState = layer->getState();
const auto* layerFEState = layer->getLayerFE().getCompositionState();
auto& layerFE = layer->getLayerFE();
+ layerFE.setWasClientComposed(nullptr);
const Region clip(viewportRegion.intersect(layerState.visibleRegion));
ALOGV("Layer: %s", layerFE.getDebugName());
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 742af58..1bb9d0eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -377,6 +377,7 @@
auto requestedCompositionType = outputIndependentState->compositionType;
if (requestedCompositionType == Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+ // this should never happen, as SOLID_COLOR is skipped from caching, b/230073351
requestedCompositionType = Composition::DEVICE;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index d15b0a7..641b806 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -388,6 +388,12 @@
[](const Layer& layer) { return layer.getState()->isProtected(); });
}
+bool CachedSet::hasSolidColorLayers() const {
+ return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
+ return layer.getState()->hasSolidColorCompositionType();
+ });
+}
+
void CachedSet::dump(std::string& result) const {
const auto now = std::chrono::steady_clock::now();
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 250f648..1062b70 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -498,6 +498,13 @@
}
}
+ for (const CachedSet& layer : mLayers) {
+ if (layer.hasSolidColorLayers()) {
+ ATRACE_NAME("layer->hasSolidColorLayers()");
+ return;
+ }
+ }
+
std::vector<Run> runs = findCandidateRuns(now);
std::optional<Run> bestRun = findBestRun(runs);
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index c8b6d44..579636f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -45,17 +45,17 @@
MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
- MOCK_METHOD(void, setValidateTiming,
+ MOCK_METHOD(void, setHwcValidateTiming,
(DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
(override));
- MOCK_METHOD(void, setPresentTiming,
+ MOCK_METHOD(void, setHwcPresentTiming,
(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setPresentDelayedTime,
+ MOCK_METHOD(void, setHwcPresentDelayedTime,
(DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime));
MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a915b61..8680900 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -211,6 +211,7 @@
to_string(getId()).c_str());
return BAD_VALUE;
}
+ mNumModeSwitchesInPolicy++;
mUpcomingActiveMode = info;
ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
@@ -537,6 +538,27 @@
mDesiredActiveModeChanged = false;
}
+status_t DisplayDevice::setRefreshRatePolicy(
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
+ const auto oldPolicy = mRefreshRateConfigs->getCurrentPolicy();
+ const status_t setPolicyResult = overridePolicy
+ ? mRefreshRateConfigs->setOverridePolicy(policy)
+ : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+
+ if (setPolicyResult == OK) {
+ const int numModeChanges = mNumModeSwitchesInPolicy.exchange(0);
+
+ ALOGI("Display %s policy changed\n"
+ "Previous: {%s}\n"
+ "Current: {%s}\n"
+ "%d mode changes were performed under the previous policy",
+ to_string(getId()).c_str(), oldPolicy.toString().c_str(),
+ policy ? policy->toString().c_str() : "null", numModeChanges);
+ }
+
+ return setPolicyResult;
+}
+
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d5d87b4..2161436 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -249,6 +249,10 @@
nsecs_t getVsyncPeriodFromHWC() const;
nsecs_t getRefreshTimestamp() const;
+ status_t setRefreshRatePolicy(
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
+ bool overridePolicy);
+
// release HWC resources (if any) for removable displays
void disconnect();
@@ -303,6 +307,8 @@
TracedOrdinal<bool> mDesiredActiveModeChanged
GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
+
+ std::atomic_int mNumModeSwitchesInPolicy = 0;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 4c0a942..40b1132 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -238,7 +238,8 @@
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->sendActualWorkDuration(*predictedDuration, systemTime());
+ halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(),
+ systemTime());
}
}
}
@@ -287,18 +288,18 @@
displayData.gpuStartTime = systemTime();
}
-void PowerAdvisor::setValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
- nsecs_t validateEndTime) {
+void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+ nsecs_t validateEndTime) {
DisplayTimingData& displayData = mDisplayTimingData[displayId];
- displayData.validateStartTime = validateStartTime;
- displayData.validateEndTime = validateEndTime;
+ displayData.hwcValidateStartTime = validateStartTime;
+ displayData.hwcValidateEndTime = validateEndTime;
}
-void PowerAdvisor::setPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) {
+void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) {
DisplayTimingData& displayData = mDisplayTimingData[displayId];
- displayData.presentStartTime = presentStartTime;
- displayData.presentEndTime = presentEndTime;
+ displayData.hwcPresentStartTime = presentStartTime;
+ displayData.hwcPresentEndTime = presentEndTime;
}
void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) {
@@ -318,9 +319,9 @@
mFrameDelayDuration = frameDelayDuration;
}
-void PowerAdvisor::setPresentDelayedTime(
+void PowerAdvisor::setHwcPresentDelayedTime(
DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) {
- mDisplayTimingData[displayId].presentDelayedTime =
+ mDisplayTimingData[displayId].hwcPresentDelayedTime =
(earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime();
}
@@ -331,10 +332,11 @@
void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
mLastCompositeEndTime = compositeEnd;
// calculate the postcomp time here as well
- std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::presentEndTime);
+ std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime);
DisplayTimingData& timingData = mDisplayTimingData[displays.back()];
mLastPostcompDuration = compositeEnd -
- (timingData.skippedValidate ? *timingData.validateEndTime : *timingData.presentEndTime);
+ (timingData.skippedValidate ? *timingData.hwcValidateEndTime
+ : *timingData.hwcPresentEndTime);
}
void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
@@ -390,7 +392,7 @@
// The timing info for the previously calculated display, if there was one
std::optional<DisplayTimeline> previousDisplayReferenceTiming;
std::vector<DisplayId>&& displayIds =
- getOrderedDisplayIds(&DisplayTimingData::presentStartTime);
+ getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
DisplayTimeline referenceTiming, estimatedTiming;
// Iterate over the displays in the same order they are presented
@@ -402,27 +404,26 @@
auto& displayData = mDisplayTimingData.at(displayId);
referenceTiming = displayData.calculateDisplayTimeline(referenceFenceTime);
- // If this is the first display, add the pre-present time to the total
+ // If this is the first display, include the duration before hwc present starts
if (!previousDisplayReferenceTiming.has_value()) {
- estimatedEndTime += referenceTiming.prePresentTime - referenceFrameStartTime;
- } else { // Otherwise add last display's postprocessing time to the total
- estimatedEndTime += referenceTiming.prePresentTime -
- previousDisplayReferenceTiming->postPresentTime;
+ estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime;
+ } else { // Otherwise add the time since last display's hwc present finished
+ estimatedEndTime += referenceTiming.hwcPresentStartTime -
+ previousDisplayReferenceTiming->hwcPresentEndTime;
}
estimatedTiming = referenceTiming.estimateTimelineFromReference(mExpectedPresentTimes[-1],
estimatedEndTime);
// Update predicted present finish time with this display's present time
- estimatedEndTime = estimatedTiming.postPresentTime;
+ estimatedEndTime = estimatedTiming.hwcPresentEndTime;
// Track how long we spent waiting for the fence, can be excluded from the timing estimate
- idleDuration += estimatedTiming.probablyWaitsForFence
- ? mExpectedPresentTimes[-1] - estimatedTiming.preFenceWaitTime
+ idleDuration += estimatedTiming.probablyWaitsForReleaseFence
+ ? mExpectedPresentTimes[-1] - estimatedTiming.releaseFenceWaitStartTime
: 0;
// Track how long we spent waiting to present, can be excluded from the timing estimate
- idleDuration +=
- !earlyHint ? referenceTiming.presentStartTime - referenceTiming.prePresentTime : 0;
+ idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration;
// Estimate the reference frame's gpu timing
auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
@@ -431,7 +432,7 @@
// Estimate the prediction frame's gpu end time from the reference frame
estimatedGpuEndTime =
- std::max(estimatedTiming.prePresentTime, estimatedGpuEndTime.value_or(0)) +
+ std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) +
gpuTiming->duration;
}
previousDisplayReferenceTiming = referenceTiming;
@@ -470,48 +471,55 @@
PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
nsecs_t fenceTime, nsecs_t displayStartTime) {
DisplayTimeline estimated;
- estimated.prePresentTime = displayStartTime;
+ estimated.hwcPresentStartTime = displayStartTime;
// We don't predict waiting for vsync alignment yet
- estimated.presentStartTime = estimated.prePresentTime;
+ estimated.hwcPresentDelayDuration = 0;
// For now just re-use last frame's post-present duration and assume it will not change much
// How long we expect to run before we start waiting for the fence
- estimated.preFenceWaitTime = estimated.presentStartTime + (preFenceWaitTime - presentStartTime);
- estimated.probablyWaitsForFence = fenceTime > estimated.preFenceWaitTime;
- estimated.postPresentTime = postFenceDuration +
- (estimated.probablyWaitsForFence ? fenceTime : estimated.preFenceWaitTime);
+ // If it's the early hint we exclude time we spent waiting for a vsync, otherwise don't
+ estimated.releaseFenceWaitStartTime = estimated.hwcPresentStartTime +
+ (releaseFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration));
+ estimated.probablyWaitsForReleaseFence = fenceTime > estimated.releaseFenceWaitStartTime;
+ estimated.hwcPresentEndTime = postReleaseFenceHwcPresentDuration +
+ (estimated.probablyWaitsForReleaseFence ? fenceTime
+ : estimated.releaseFenceWaitStartTime);
return estimated;
}
PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
nsecs_t fenceTime) {
DisplayTimeline timeline;
- // How long between calling present from flinger and trying to wait on the fence in HWC
- const nsecs_t preFenceWaitDelay =
- (skippedValidate ? kPrefenceDelaySkippedValidate : kPrefenceDelayValidated).count();
+ // How long between calling hwc present and trying to wait on the fence
+ const nsecs_t fenceWaitStartDelay =
+ (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated)
+ .count();
- // Did our reference frame wait for an earliest present time before calling the HWC
- const bool waitedOnPresentTime = presentDelayedTime.has_value() &&
- *presentDelayedTime > *presentStartTime && *presentDelayedTime < *presentEndTime;
+ // Did our reference frame wait for an appropriate vsync before calling into hwc
+ const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
+ *hwcPresentDelayedTime > *hwcPresentStartTime &&
+ *hwcPresentDelayedTime < *hwcPresentEndTime;
// Use validate start here if we skipped it because we did validate + present together
- timeline.prePresentTime = skippedValidate ? *validateStartTime : *presentStartTime;
+ timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime;
// Use validate end here if we skipped it because we did validate + present together
- timeline.postPresentTime = skippedValidate ? *validateEndTime : *presentEndTime;
+ timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime;
- // When we think we started waiting for the fence after calling into present
- // This is after any time spent waiting for the earliest present time
- timeline.presentStartTime =
- (waitedOnPresentTime ? *presentDelayedTime : timeline.prePresentTime);
- timeline.preFenceWaitTime = timeline.presentStartTime + preFenceWaitDelay;
- timeline.probablyWaitsForFence =
- fenceTime > timeline.preFenceWaitTime && fenceTime < timeline.postPresentTime;
+ // How long hwc present was delayed waiting for the next appropriate vsync
+ timeline.hwcPresentDelayDuration =
+ (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0);
+ // When we started waiting for the release fence after calling into hwc present
+ timeline.releaseFenceWaitStartTime =
+ timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
+ timeline.probablyWaitsForReleaseFence = fenceTime > timeline.releaseFenceWaitStartTime &&
+ fenceTime < timeline.hwcPresentEndTime;
- // How long we ran after we finished waiting for the fence but before present happened
- timeline.postFenceDuration = timeline.postPresentTime -
- (timeline.probablyWaitsForFence ? fenceTime : timeline.preFenceWaitTime);
+ // How long we ran after we finished waiting for the fence but before hwc present finished
+ timeline.postReleaseFenceHwcPresentDuration = timeline.hwcPresentEndTime -
+ (timeline.probablyWaitsForReleaseFence ? fenceTime
+ : timeline.releaseFenceWaitStartTime);
return timeline;
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 8e1e33f..bdc7927 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -64,20 +64,20 @@
virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0;
// Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
- // Reports the start and end times of a present call this frame for a given display
- virtual void setValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
- nsecs_t validateEndTime) = 0;
- // Reports the start and end times of a present call this frame for a given display
- virtual void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) = 0;
+ // Reports the start and end times of a hwc validate call this frame for a given display
+ virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+ nsecs_t validateEndTime) = 0;
+ // Reports the start and end times of a hwc present call this frame for a given display
+ virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) = 0;
virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0;
// Reports whether a display used client composition this frame
virtual void setRequiresClientComposition(DisplayId displayId,
bool requiresClientComposition) = 0;
// Reports whether a given display skipped validation this frame
virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
- // Reports how much a given display delayed its present call this frame
- virtual void setPresentDelayedTime(
+ // Reports when a hwc present is delayed, and the time that it will resume
+ virtual void setHwcPresentDelayedTime(
DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0;
// Reports the start delay for SurfaceFlinger this frame
virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0;
@@ -132,14 +132,14 @@
void enablePowerHint(bool enabled) override;
bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime);
- void setValidateTiming(DisplayId displayId, nsecs_t valiateStartTime,
- nsecs_t validateEndTime) override;
- void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) override;
+ void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime,
+ nsecs_t validateEndTime) override;
+ void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) override;
void setSkippedValidate(DisplayId displayId, bool skipped) override;
void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
void setExpectedPresentTime(nsecs_t expectedPresentTime) override;
- void setPresentDelayedTime(
+ void setHwcPresentDelayedTime(
DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime) override;
@@ -166,17 +166,19 @@
// Higher-level timing data used for estimation
struct DisplayTimeline {
- nsecs_t prePresentTime = -1;
- nsecs_t postPresentTime = -1;
- // Usually equals prePresentTime but can be delayed if we wait for the next valid vsync
- nsecs_t presentStartTime = -1;
- // When we think we started waiting for the fence after calling into present and
+ // The start of hwc present, or the start of validate if it happened there instead
+ nsecs_t hwcPresentStartTime = -1;
+ // The end of hwc present or validate, whichever one actually presented
+ nsecs_t hwcPresentEndTime = -1;
+ // How long the actual hwc present was delayed after hwcPresentStartTime
+ nsecs_t hwcPresentDelayDuration = 0;
+ // When we think we started waiting for the release fence after calling into hwc present and
// after potentially waiting for the earliest present time
- nsecs_t preFenceWaitTime = -1;
- // How long we ran after we finished waiting for the fence but before present happened
- nsecs_t postFenceDuration = 0;
+ nsecs_t releaseFenceWaitStartTime = -1;
+ // How long we ran after we finished waiting for the fence but before hwc present finished
+ nsecs_t postReleaseFenceHwcPresentDuration = 0;
// Are we likely to have waited for the present fence during composition
- bool probablyWaitsForFence = false;
+ bool probablyWaitsForReleaseFence = false;
// Estimate one frame's timeline from that of a previous frame
DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime);
};
@@ -192,11 +194,11 @@
std::optional<nsecs_t> gpuStartTime;
std::optional<nsecs_t> lastValidGpuEndTime;
std::optional<nsecs_t> lastValidGpuStartTime;
- std::optional<nsecs_t> presentStartTime;
- std::optional<nsecs_t> presentEndTime;
- std::optional<nsecs_t> validateStartTime;
- std::optional<nsecs_t> validateEndTime;
- std::optional<nsecs_t> presentDelayedTime;
+ std::optional<nsecs_t> hwcPresentStartTime;
+ std::optional<nsecs_t> hwcPresentEndTime;
+ std::optional<nsecs_t> hwcValidateStartTime;
+ std::optional<nsecs_t> hwcValidateEndTime;
+ std::optional<nsecs_t> hwcPresentDelayedTime;
bool usedClientComposition = false;
bool skippedValidate = false;
// Calculate high-level timing milestones from more granular display timing data
@@ -258,13 +260,13 @@
// An adjustable safety margin which moves the "target" earlier to allow flinger to
// go a bit over without dropping a frame, especially since we can't measure
- // the exact time HWC finishes composition so "actual" durations are measured
+ // the exact time hwc finishes composition so "actual" durations are measured
// from the end of present() instead, which is a bit later.
static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms;
// How long we expect hwc to run after the present call until it waits for the fence
- static constexpr const std::chrono::nanoseconds kPrefenceDelayValidated = 150us;
- static constexpr const std::chrono::nanoseconds kPrefenceDelaySkippedValidate = 250us;
+ static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us;
+ static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us;
};
class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ed4a94..be16942 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2194,6 +2194,37 @@
return getCroppedBufferSize(getDrawingState());
}
+// Applies the given transform to the region, while protecting against overflows caused by any
+// offsets. If applying the offset in the transform to any of the Rects in the region would result
+// in an overflow, they are not added to the output Region.
+static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
+ const std::string& debugWindowName) {
+ // Round the translation using the same rounding strategy used by ui::Transform.
+ const auto tx = static_cast<int32_t>(t.tx() + 0.5);
+ const auto ty = static_cast<int32_t>(t.ty() + 0.5);
+
+ ui::Transform transformWithoutOffset = t;
+ transformWithoutOffset.set(0.f, 0.f);
+
+ const Region transformed = transformWithoutOffset.transform(r);
+
+ // Apply the translation to each of the Rects in the region while discarding any that overflow.
+ Region ret;
+ for (const auto& rect : transformed) {
+ Rect newRect;
+ if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
+ __builtin_add_overflow(rect.top, ty, &newRect.top) ||
+ __builtin_add_overflow(rect.right, tx, &newRect.right) ||
+ __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
+ ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
+ debugWindowName.c_str());
+ continue;
+ }
+ ret.orSelf(newRect);
+ }
+ return ret;
+}
+
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
@@ -2256,7 +2287,8 @@
info.transform = inputToDisplay.inverse();
// The touchable region is specified in the input coordinate space. Change it to display space.
- info.touchableRegion = inputToDisplay.transform(info.touchableRegion);
+ info.touchableRegion =
+ transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3988e51..24abad9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -620,6 +620,7 @@
void setWasClientComposed(const sp<Fence>& fence) override {
mLastClientCompositionFence = fence;
+ mClearClientCompositionFenceOnLayerDisplayed = false;
}
const char* getDebugName() const override;
@@ -1035,7 +1036,7 @@
mutable bool mDrawingStateModified = false;
sp<Fence> mLastClientCompositionFence;
- bool mAlreadyDisplayedThisCompose = false;
+ bool mClearClientCompositionFenceOnLayerDisplayed = false;
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index cbea77e..639ba5a 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -177,6 +177,11 @@
}
binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
+ std::scoped_lock lock(mLock);
+ if (mChannel.initCheck() != NO_ERROR) {
+ return binder::Status::fromStatusT(NAME_NOT_FOUND);
+ }
+
outChannel->setReceiveFd(mChannel.moveReceiveFd());
outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
return binder::Status::ok();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c406478..adb96fd 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -112,7 +112,8 @@
private:
virtual void onFirstRef();
EventThread* const mEventThread;
- gui::BitTube mChannel;
+ std::mutex mLock;
+ gui::BitTube mChannel GUARDED_BY(mLock);
std::vector<DisplayEventReceiver::Event> mPendingEvents;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 37f0fec..727cb08 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <ftl/fake_guard.h>
#include <gui/WindowInfo.h>
#include <system/window.h>
#include <ui/DisplayStatInfo.h>
@@ -94,9 +95,13 @@
}
void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> configs) {
+ // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
{
- // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
- std::scoped_lock lock(mRefreshRateConfigsLock);
+ // mRefreshRateConfigsLock is not locked here to avoid the deadlock
+ // as the callback can attempt to acquire the lock before stopIdleTimer can finish
+ // the execution. It's safe to FakeGuard as main thread is the only thread that
+ // writes to the mRefreshRateConfigs.
+ ftl::FakeGuard guard(mRefreshRateConfigsLock);
if (mRefreshRateConfigs) {
mRefreshRateConfigs->stopIdleTimer();
mRefreshRateConfigs->clearIdleTimerCallbacks();
@@ -554,11 +559,12 @@
}
}
-void Scheduler::setDisplayPowerState(bool normal) {
+void Scheduler::setDisplayPowerMode(hal::PowerMode powerMode) {
{
std::lock_guard<std::mutex> lock(mPolicyLock);
- mPolicy.isDisplayPowerStateNormal = normal;
+ mPolicy.displayPowerMode = powerMode;
}
+ mVsyncSchedule->getController().setDisplayPowerMode(powerMode);
if (mDisplayPowerTimer) {
mDisplayPowerTimer->reset();
@@ -706,7 +712,8 @@
// If Display Power is not in normal operation we want to be in performance mode. When coming
// back to normal mode, a grace period is given with DisplayPowerTimer.
if (mDisplayPowerTimer &&
- (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
+ (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+ mPolicy.displayPowerTimer == TimerState::Reset)) {
constexpr GlobalSignals kNoSignals;
return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0c72124..a8043bf 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -186,7 +186,7 @@
// Indicates that touch interaction is taking place.
void onTouchHint();
- void setDisplayPowerState(bool normal);
+ void setDisplayPowerMode(hal::PowerMode powerMode);
VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
@@ -325,7 +325,7 @@
TimerState idleTimer = TimerState::Reset;
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
- bool isDisplayPowerStateNormal = true;
+ hal::PowerMode displayPowerMode = hal::PowerMode::ON;
// Chosen display mode.
DisplayModePtr mode;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index bdcab51..13cd304 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -146,6 +146,11 @@
return false;
}
+ if (mDisplayPowerMode == hal::PowerMode::DOZE ||
+ mDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
+ return true;
+ }
+
if (!mLastHwVsync && !HwcVsyncPeriod) {
return false;
}
@@ -206,6 +211,11 @@
return mMoreSamplesNeeded;
}
+void VSyncReactor::setDisplayPowerMode(hal::PowerMode powerMode) {
+ std::scoped_lock lock(mMutex);
+ mDisplayPowerMode = powerMode;
+}
+
void VSyncReactor::dump(std::string& result) const {
std::lock_guard lock(mMutex);
StringAppendF(&result, "VsyncReactor in use\n");
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 6a1950a..4501487 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -49,6 +49,8 @@
bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
bool* periodFlushed) final;
+ void setDisplayPowerMode(hal::PowerMode powerMode) final;
+
void dump(std::string& result) const final;
private:
@@ -73,6 +75,8 @@
std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
+ hal::PowerMode mDisplayPowerMode GUARDED_BY(mMutex) = hal::PowerMode::ON;
+
const bool mSupportKernelIdleTimer = false;
};
diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h
index 59f6537..726a420 100644
--- a/services/surfaceflinger/Scheduler/VsyncController.h
+++ b/services/surfaceflinger/Scheduler/VsyncController.h
@@ -18,7 +18,10 @@
#include <cstddef>
#include <memory>
+#include <mutex>
+#include <DisplayHardware/HWComposer.h>
+#include <DisplayHardware/Hal.h>
#include <ui/FenceTime.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -70,6 +73,13 @@
*/
virtual void setIgnorePresentFences(bool ignore) = 0;
+ /*
+ * Sets the primary display power mode to the controller.
+ *
+ * \param [in] powerMode
+ */
+ virtual void setDisplayPowerMode(hal::PowerMode powerMode) = 0;
+
virtual void dump(std::string& result) const = 0;
protected:
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index e611658..3a918a1 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <scheduler/Fps.h>
#include <scheduler/Timer.h>
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5cf9558..b7d6968 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4947,7 +4947,7 @@
if (isDisplayActiveLocked(display)) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
- mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
+ mScheduler->setDisplayPowerMode(mode);
}
ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
@@ -6913,9 +6913,7 @@
return NO_ERROR;
}
- status_t setPolicyResult = overridePolicy
- ? display->refreshRateConfigs().setOverridePolicy(policy)
- : display->refreshRateConfigs().setDisplayManagerPolicy(*policy);
+ const status_t setPolicyResult = display->setRefreshRatePolicy(policy, overridePolicy);
if (setPolicyResult < 0) {
return BAD_VALUE;
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index aab2795..93c809e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,8 +159,8 @@
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- constexpr bool kPowerStateNormal = true;
- mScheduler->setDisplayPowerState(kPowerStateNormal);
+ constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+ mScheduler->setDisplayPowerMode(kPowerModeOn);
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
@@ -226,8 +226,8 @@
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
- constexpr bool kPowerStateNormal = true;
- mScheduler->setDisplayPowerState(kPowerStateNormal);
+ constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+ mScheduler->setDisplayPowerMode(kPowerModeOn);
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4eb9055..30a3f9a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -349,6 +349,23 @@
}
}
+TEST_F(VSyncReactorTest, addHwVsyncTimestampDozePreempt) {
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+
+ mReactor.startPeriodTransition(newPeriod);
+
+ auto time = 0;
+ // If the power mode is not DOZE or DOZE_SUSPEND, it is still collecting timestamps.
+ EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ // Set power mode to DOZE to trigger period flushing.
+ mReactor.setDisplayPowerMode(hal::PowerMode::DOZE);
+ EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
auto time = 0;
bool periodFlushed = false;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 05cc544..e347883 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -43,17 +43,17 @@
MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
- MOCK_METHOD(void, setValidateTiming,
+ MOCK_METHOD(void, setHwcValidateTiming,
(DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
(override));
- MOCK_METHOD(void, setPresentTiming,
+ MOCK_METHOD(void, setHwcPresentTiming,
(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setPresentDelayedTime,
+ MOCK_METHOD(void, setHwcPresentDelayedTime,
(DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime));
MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
index 314f681..4ef91da 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
@@ -31,6 +31,7 @@
MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional<nsecs_t>, bool*));
MOCK_METHOD1(startPeriodTransition, void(nsecs_t));
MOCK_METHOD1(setIgnorePresentFences, void(bool));
+ MOCK_METHOD(void, setDisplayPowerMode, (hal::PowerMode), (override));
MOCK_CONST_METHOD1(dump, void(std::string&));
};