summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.cpp4
-rw-r--r--cmds/evemu-record/main.rs38
-rw-r--r--libs/binder/Android.bp2
-rw-r--r--libs/binder/OS.h3
-rw-r--r--libs/binder/OS_android.cpp9
-rw-r--r--libs/binder/Trace.cpp32
-rw-r--r--libs/binder/include/binder/Trace.h24
-rw-r--r--libs/binder/trusty/OS.cpp12
-rw-r--r--libs/binder/trusty/kernel/rules.mk2
-rw-r--r--libs/binder/trusty/rules.mk1
-rw-r--r--libs/gui/Android.bp2
-rw-r--r--libs/gui/BufferQueueConsumer.cpp38
-rw-r--r--libs/gui/LayerState.cpp4
-rw-r--r--libs/gui/include/gui/DisplayCaptureArgs.h1
-rw-r--r--libs/gui/include/gui/JankInfo.h14
-rw-r--r--libs/nativewindow/include/system/window.h32
-rw-r--r--libs/ui/Gralloc5.cpp18
-rw-r--r--services/surfaceflinger/CompositionEngine/Android.bp4
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp63
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp16
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp5
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp171
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp27
-rw-r--r--services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp13
-rw-r--r--services/surfaceflinger/DisplayHardware/HWC2.h8
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp1
-rw-r--r--services/surfaceflinger/DisplayHardware/Hal.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp9
-rw-r--r--services/surfaceflinger/DisplayRenderArea.cpp33
-rw-r--r--services/surfaceflinger/DisplayRenderArea.h4
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.cpp43
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.h8
-rw-r--r--services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp22
-rw-r--r--services/surfaceflinger/FrontEnd/RequestedLayerState.cpp2
-rw-r--r--services/surfaceflinger/Layer.cpp13
-rw-r--r--services/surfaceflinger/Layer.h4
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp4
-rw-r--r--services/surfaceflinger/RenderArea.h10
-rw-r--r--services/surfaceflinger/Scheduler/FrameRateCompatibility.h2
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.cpp2
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.cpp43
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.h12
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateSelector.cpp35
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateSelector.h7
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp25
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h3
-rw-r--r--services/surfaceflinger/ScreenCaptureOutput.cpp26
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp42
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h4
-rw-r--r--services/surfaceflinger/common/FlagManager.cpp5
-rw-r--r--services/surfaceflinger/common/include/common/FlagManager.h2
-rw-r--r--services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h7
-rw-r--r--services/surfaceflinger/surfaceflinger_flags.aconfig16
-rw-r--r--services/surfaceflinger/tests/DisplayConfigs_test.cpp74
-rw-r--r--services/surfaceflinger/tests/LayerState_test.cpp2
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp3
-rw-r--r--services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp68
-rw-r--r--services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp69
-rw-r--r--services/surfaceflinger/tests/unittests/HWComposerTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp15
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp19
-rw-r--r--services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp104
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp69
-rw-r--r--services/surfaceflinger/tests/unittests/SchedulerTest.cpp139
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp3
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp6
-rw-r--r--services/surfaceflinger/tests/unittests/TestableScheduler.h16
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h4
69 files changed, 1194 insertions, 331 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index dd0ee5fb22..83b336c62f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1035,8 +1035,6 @@ static void DoLogcat() {
CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
DoRadioLogcat();
- RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
-
/* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
"-v", "uid", "-d", "*:v"});
@@ -1243,7 +1241,7 @@ static void DumpPacketStats() {
static void DumpIpAddrAndRules() {
/* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
- RunCommand("NETWORK INTERFACES", {"ip", "link"});
+ RunCommand("NETWORK INTERFACES", {"ip", "-s", "link"});
RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
RunCommand("IP RULES", {"ip", "rule", "show"});
diff --git a/cmds/evemu-record/main.rs b/cmds/evemu-record/main.rs
index 6f5deb96b2..c30c00fcd2 100644
--- a/cmds/evemu-record/main.rs
+++ b/cmds/evemu-record/main.rs
@@ -26,7 +26,7 @@ use std::io;
use std::io::{BufRead, Write};
use std::path::PathBuf;
-use clap::Parser;
+use clap::{Parser, ValueEnum};
use nix::sys::time::TimeVal;
mod evdev;
@@ -39,6 +39,19 @@ struct Args {
device: Option<PathBuf>,
/// The file to save the recording to. Defaults to standard output.
output_file: Option<PathBuf>,
+
+ /// The base time that timestamps should be relative to (Android-specific extension)
+ #[arg(long, value_enum, default_value_t = TimestampBase::FirstEvent)]
+ timestamp_base: TimestampBase,
+}
+
+#[derive(Clone, Debug, ValueEnum)]
+enum TimestampBase {
+ /// The first event received from the device.
+ FirstEvent,
+
+ /// The time when the system booted.
+ Boot,
}
fn get_choice(max: u32) -> u32 {
@@ -149,7 +162,11 @@ fn print_device_description(
Ok(())
}
-fn print_events(device: &evdev::Device, output: &mut impl Write) -> Result<(), Box<dyn Error>> {
+fn print_events(
+ device: &evdev::Device,
+ output: &mut impl Write,
+ timestamp_base: TimestampBase,
+) -> Result<(), Box<dyn Error>> {
fn print_event(output: &mut impl Write, event: &evdev::InputEvent) -> Result<(), io::Error> {
// TODO(b/302297266): Translate events into human-readable names and add those as comments.
writeln!(
@@ -164,12 +181,15 @@ fn print_events(device: &evdev::Device, output: &mut impl Write) -> Result<(), B
Ok(())
}
let event = device.read_event()?;
- // Due to a bug in the C implementation of evemu-play [0] that has since become part of the API,
- // the timestamp of the first event in a recording shouldn't be exactly 0.0 seconds, so offset
- // it by 1µs.
- //
- // [0]: https://gitlab.freedesktop.org/libevdev/evemu/-/commit/eba96a4d2be7260b5843e65c4b99c8b06a1f4c9d
- let start_time = event.time - TimeVal::new(0, 1);
+ let start_time = match timestamp_base {
+ // Due to a bug in the C implementation of evemu-play [0] that has since become part of the
+ // API, the timestamp of the first event in a recording shouldn't be exactly 0.0 seconds,
+ // so offset it by 1µs.
+ //
+ // [0]: https://gitlab.freedesktop.org/libevdev/evemu/-/commit/eba96a4d2be7260b5843e65c4b99c8b06a1f4c9d
+ TimestampBase::FirstEvent => event.time - TimeVal::new(0, 1),
+ TimestampBase::Boot => TimeVal::new(0, 0),
+ };
print_event(output, &event.offset_time_by(start_time))?;
loop {
let event = device.read_event()?;
@@ -188,6 +208,6 @@ fn main() -> Result<(), Box<dyn Error>> {
None => Box::new(io::stdout().lock()),
};
print_device_description(&device, &mut output)?;
- print_events(&device, &mut output)?;
+ print_events(&device, &mut output, args.timestamp_base)?;
Ok(())
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index eccd5dbc3a..d73c3a4e8c 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -90,7 +90,6 @@ cc_defaults {
"Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
- "Trace.cpp",
"Utils.cpp",
"file.cpp",
],
@@ -251,7 +250,6 @@ cc_library_shared {
srcs: [
// Trusty-specific files
- "OS_android.cpp",
"trusty/OS.cpp",
"trusty/RpcServerTrusty.cpp",
"trusty/RpcTransportTipcTrusty.cpp",
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index c5f0730d6b..0035aeb205 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -24,6 +24,9 @@
namespace android::binder::os {
+void trace_begin(uint64_t tag, const char* name);
+void trace_end(uint64_t tag);
+
status_t setNonBlocking(borrowed_fd fd);
status_t getRandomBytes(uint8_t* data, size_t size);
diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp
index ad458eb705..155588d7f5 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -17,6 +17,7 @@
#include "OS.h"
#include <android-base/threads.h>
+#include <cutils/trace.h>
#include <utils/misc.h>
namespace android::binder::os {
@@ -34,4 +35,12 @@ bool report_sysprop_change() {
return true;
}
+void trace_begin(uint64_t tag, const char* name) {
+ atrace_begin(tag, name);
+}
+
+void trace_end(uint64_t tag) {
+ atrace_end(tag);
+}
+
} // namespace android::binder::os
diff --git a/libs/binder/Trace.cpp b/libs/binder/Trace.cpp
deleted file mode 100644
index 1ebfa1a165..0000000000
--- a/libs/binder/Trace.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 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 <binder/Trace.h>
-#include <cutils/trace.h>
-
-namespace android {
-namespace binder {
-
-void atrace_begin(uint64_t tag, const char* name) {
- ::atrace_begin(tag, name);
-}
-
-void atrace_end(uint64_t tag) {
- ::atrace_end(tag);
-}
-
-} // namespace binder
-} // namespace android
diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h
index 99378428ad..95318b2bf6 100644
--- a/libs/binder/include/binder/Trace.h
+++ b/libs/binder/include/binder/Trace.h
@@ -16,22 +16,36 @@
#pragma once
-#include <cutils/trace.h>
#include <stdint.h>
+#if __has_include(<cutils/trace.h>)
+#include <cutils/trace.h>
+#endif
+
+#ifdef ATRACE_TAG_AIDL
+#if ATRACE_TAG_AIDL != (1 << 24)
+#error "Mismatched ATRACE_TAG_AIDL definitions"
+#endif
+#else
+#define ATRACE_TAG_AIDL (1 << 24)
+#endif
+
namespace android {
namespace binder {
+// Forward declarations from internal OS.h
+namespace os {
// Trampoline functions allowing generated aidls to trace binder transactions without depending on
// libcutils/libutils
-void atrace_begin(uint64_t tag, const char* name);
-void atrace_end(uint64_t tag);
+void trace_begin(uint64_t tag, const char* name);
+void trace_end(uint64_t tag);
+} // namespace os
class ScopedTrace {
public:
- inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) { atrace_begin(mTag, name); }
+ inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) { os::trace_begin(mTag, name); }
- inline ~ScopedTrace() { atrace_end(mTag); }
+ inline ~ScopedTrace() { os::trace_end(mTag); }
private:
uint64_t mTag;
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index ca14286d74..99da1ebc6d 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -31,6 +31,18 @@ using android::binder::unique_fd;
namespace android::binder::os {
+void trace_begin(uint64_t, const char*) {}
+
+void trace_end(uint64_t) {}
+
+uint64_t GetThreadId() {
+ return 0;
+}
+
+bool report_sysprop_change() {
+ return false;
+}
+
status_t setNonBlocking(borrowed_fd /*fd*/) {
// Trusty IPC syscalls are all non-blocking by default.
return OK;
diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk
index d2b37aa8f6..69737fa102 100644
--- a/libs/binder/trusty/kernel/rules.mk
+++ b/libs/binder/trusty/kernel/rules.mk
@@ -24,13 +24,13 @@ LIBUTILS_DIR := system/core/libutils
FMTLIB_DIR := external/fmtlib
MODULE_SRCS := \
+ $(LOCAL_DIR)/../OS.cpp \
$(LOCAL_DIR)/../TrustyStatus.cpp \
$(LIBBINDER_DIR)/Binder.cpp \
$(LIBBINDER_DIR)/BpBinder.cpp \
$(LIBBINDER_DIR)/FdTrigger.cpp \
$(LIBBINDER_DIR)/IInterface.cpp \
$(LIBBINDER_DIR)/IResultReceiver.cpp \
- $(LIBBINDER_DIR)/OS_android.cpp \
$(LIBBINDER_DIR)/Parcel.cpp \
$(LIBBINDER_DIR)/Stability.cpp \
$(LIBBINDER_DIR)/Status.cpp \
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
index dbddbe16e2..96c66a8be4 100644
--- a/libs/binder/trusty/rules.mk
+++ b/libs/binder/trusty/rules.mk
@@ -34,7 +34,6 @@ MODULE_SRCS := \
$(LIBBINDER_DIR)/FdTrigger.cpp \
$(LIBBINDER_DIR)/IInterface.cpp \
$(LIBBINDER_DIR)/IResultReceiver.cpp \
- $(LIBBINDER_DIR)/OS_android.cpp \
$(LIBBINDER_DIR)/Parcel.cpp \
$(LIBBINDER_DIR)/ParcelFileDescriptor.cpp \
$(LIBBINDER_DIR)/RpcServer.cpp \
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index c84ee1f9da..44a9e52d5b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -423,10 +423,10 @@ cc_defaults {
"libhidlbase",
"liblog",
"libnativewindow",
+ "libselinux",
"libsync",
"libui",
"libutils",
- "libvndksupport",
],
static_libs: [
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index b6a47fb4e9..744201a5df 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,13 +36,45 @@
#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>
-#ifndef __ANDROID_VNDK__
+#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER)
#include <binder/PermissionCache.h>
-#include <vndksupport/linker.h>
+#include <selinux/android.h>
+#include <selinux/selinux.h>
#endif
#include <system/window.h>
+namespace {
+#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER)
+int selinux_log_suppress_callback(int, const char*, ...) { // NOLINT
+ // DO NOTHING
+ return 0;
+}
+
+bool hasAccessToPermissionService() {
+ char* ctx;
+
+ if (getcon(&ctx) == -1) {
+ // Failed to get current selinux context
+ return false;
+ }
+
+ union selinux_callback cb;
+
+ cb.func_log = selinux_log_suppress_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ bool hasAccess = selinux_check_access(ctx, "u:object_r:permission_service:s0",
+ "service_manager", "find", NULL) == 0;
+ freecon(ctx);
+ cb.func_log = hasAccess ? selinux_log_callback : selinux_vendor_log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ return hasAccess;
+}
+#endif
+} // namespace
+
namespace android {
// Macros for include BufferQueueCore information in log messages
@@ -814,7 +846,7 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul
// the PermissionController. We need to do a runtime check as well, since
// the system variant of libgui can be loaded in a vendor process. For eg:
// if a HAL uses an llndk library that depends on libgui (libmediandk etc).
- if (!android_is_in_vendor_process()) {
+ if (hasAccessToPermissionService()) {
const pid_t pid = BufferQueueThreadState::getCallingPid();
if ((uid != shellUid) &&
!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fd8fc8d123..38fab9cdaa 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,7 +86,7 @@ layer_state_t::layer_state_t()
defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT),
frameRateCategorySmoothSwitchOnly(false),
- frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF),
+ frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_PROPAGATE),
fixedTransformHint(ui::Transform::ROT_INVALID),
autoRefresh(false),
isTrustedOverlay(false),
@@ -930,7 +930,6 @@ status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const {
SAFE_PARCEL(output->writeStrongBinder, displayToken);
SAFE_PARCEL(output->writeUint32, width);
SAFE_PARCEL(output->writeUint32, height);
- SAFE_PARCEL(output->writeBool, useIdentityTransform);
return NO_ERROR;
}
@@ -940,7 +939,6 @@ status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) {
SAFE_PARCEL(input->readStrongBinder, &displayToken);
SAFE_PARCEL(input->readUint32, &width);
SAFE_PARCEL(input->readUint32, &height);
- SAFE_PARCEL(input->readBool, &useIdentityTransform);
return NO_ERROR;
}
diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h
index 2676e0a338..e29ce41bd5 100644
--- a/libs/gui/include/gui/DisplayCaptureArgs.h
+++ b/libs/gui/include/gui/DisplayCaptureArgs.h
@@ -76,7 +76,6 @@ struct DisplayCaptureArgs : CaptureArgs {
sp<IBinder> displayToken;
uint32_t width{0};
uint32_t height{0};
- bool useIdentityTransform{false};
status_t writeToParcel(Parcel* output) const override;
status_t readFromParcel(const Parcel* input) override;
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index bf354e7bb4..1fc80c30d7 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -18,7 +18,7 @@
namespace android {
-// Jank information tracked by SurfaceFlinger(SF) for perfetto tracing and telemetry.
+// Jank type tracked by SurfaceFlinger(SF) for Perfetto tracing and telemetry.
enum JankType {
// No Jank
None = 0x0,
@@ -50,4 +50,16 @@ enum JankType {
Dropped = 0x200,
};
+// Jank severity type tracked by SurfaceFlinger(SF) for Perfetto tracing and telemetry.
+enum class JankSeverityType {
+ // Unknown: not enough information to classify the severity of a jank
+ Unknown = 0,
+ // None: no jank
+ None = 1,
+ // Partial: jank caused by missing the deadline by less than the app's frame interval
+ Partial = 2,
+ // Full: jank caused by missing the deadline by more than the app's frame interval
+ Full = 3,
+};
+
} // namespace android
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b068f4807c..a98ea86073 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1057,7 +1057,12 @@ enum {
/**
* This surface will vote for the minimum refresh rate.
*/
- ANATIVEWINDOW_FRAME_RATE_MIN
+ ANATIVEWINDOW_FRAME_RATE_MIN,
+
+ /**
+ * The surface requests a frame rate that is greater than or equal to `frameRate`.
+ */
+ ANATIVEWINDOW_FRAME_RATE_GTE
};
/*
@@ -1103,17 +1108,34 @@ enum {
enum {
/**
* Default value. The layer uses its own frame rate specifications, assuming it has any
- * specifications, instead of its parent's.
+ * specifications, instead of its parent's. If it does not have its own frame rate
+ * specifications, it will try to use its parent's. It will propagate its specifications to any
+ * descendants that do not have their own.
+ *
+ * However, FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN on an ancestor layer
+ * supersedes this behavior, meaning that this layer will inherit frame rate specifications
+ * regardless of whether it has its own.
*/
- ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF = 0,
+ ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_PROPAGATE = 0,
/**
* The layer's frame rate specifications will propagate to and override those of its descendant
* layers.
- * The layer with this strategy has the ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF
- * behavior for itself.
+ *
+ * The layer itself has the FRAME_RATE_SELECTION_STRATEGY_PROPAGATE behavior.
+ * Thus, ancestor layer that also has the strategy
+ * FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN will override this layer's
+ * frame rate specifications.
*/
ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN = 1,
+
+ /**
+ * The layer's frame rate specifications will not propagate to its descendant
+ * layers, even if the descendant layer has no frame rate specifications.
+ * However, FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN on an ancestor
+ * layer supersedes this behavior.
+ */
+ ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF = 2,
};
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
diff --git a/libs/ui/Gralloc5.cpp b/libs/ui/Gralloc5.cpp
index 37ebfc4617..2ec6d18fda 100644
--- a/libs/ui/Gralloc5.cpp
+++ b/libs/ui/Gralloc5.cpp
@@ -518,14 +518,16 @@ status_t Gralloc5Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32
}
}
{
- auto value =
- getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(mMapper,
- bufferHandle);
- if (static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(format) !=
- value) {
- ALOGW("Format didn't match, expected %d got %s", format,
- value.has_value() ? toString(*value).c_str() : "<null>");
- return BAD_VALUE;
+ auto expected = static_cast<APixelFormat>(format);
+ if (expected != APixelFormat::IMPLEMENTATION_DEFINED) {
+ auto value =
+ getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(mMapper,
+ bufferHandle);
+ if (expected != value) {
+ ALOGW("Format didn't match, expected %d got %s", format,
+ value.has_value() ? toString(*value).c_str() : "<null>");
+ return BAD_VALUE;
+ }
}
}
{
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 455e623c37..e316190499 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -127,6 +127,10 @@ cc_library {
cc_test {
name: "libcompositionengine_test",
test_suites: ["device-tests"],
+ include_dirs: [
+ "frameworks/native/services/surfaceflinger/common/include",
+ "frameworks/native/services/surfaceflinger/tests/unittests",
+ ],
defaults: ["libcompositionengine_defaults"],
srcs: [
"tests/planner/CachedSetTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index ce2b96fc2b..1f241b091c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -227,6 +227,7 @@ public:
// Returns the bit-set of differing fields between this LayerState and another LayerState.
// This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers.
ftl::Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
+ bool isSourceCropSizeEqual(const LayerState& other) const;
compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; }
int32_t getId() const { return mId.get(); }
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 748d87bdc3..7be5fe323a 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -90,29 +90,37 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const {
}
namespace {
-int numDisplaysWithOffloadPresentSupport(const CompositionRefreshArgs& args) {
- if (!FlagManager::getInstance().multithreaded_present() || args.outputs.size() < 2) {
- return 0;
+void offloadOutputs(Outputs& outputs) {
+ if (!FlagManager::getInstance().multithreaded_present() || outputs.size() < 2) {
+ return;
}
- int numEligibleDisplays = 0;
- // Only run present in multiple threads if all HWC-enabled displays
- // being refreshed support it.
- if (!std::all_of(args.outputs.begin(), args.outputs.end(),
- [&numEligibleDisplays](const auto& output) {
- if (!ftl::Optional(output->getDisplayId())
- .and_then(HalDisplayId::tryCast)) {
- // Not HWC-enabled, so it is always
- // client-composited.
- return true;
- }
- const bool support = output->supportsOffloadPresent();
- numEligibleDisplays += static_cast<int>(support);
- return support;
- })) {
- return 0;
+ ui::PhysicalDisplayVector<compositionengine::Output*> outputsToOffload;
+ for (const auto& output : outputs) {
+ if (!ftl::Optional(output->getDisplayId()).and_then(HalDisplayId::tryCast)) {
+ // Not HWC-enabled, so it is always client-composited. No need to offload.
+ continue;
+ }
+
+ // Only run present in multiple threads if all HWC-enabled displays
+ // being refreshed support it.
+ if (!output->supportsOffloadPresent()) {
+ return;
+ }
+ outputsToOffload.push_back(output.get());
+ }
+
+ if (outputsToOffload.size() < 2) {
+ return;
+ }
+
+ // Leave the last eligible display on the main thread, which will
+ // allow it to run concurrently without an extra thread hop.
+ outputsToOffload.pop_back();
+
+ for (compositionengine::Output* output : outputsToOffload) {
+ output->offloadPresentNextFrame();
}
- return numEligibleDisplays;
}
} // namespace
@@ -136,20 +144,7 @@ void CompositionEngine::present(CompositionRefreshArgs& args) {
// Offloading the HWC call for `present` allows us to simultaneously call it
// on multiple displays. This is desirable because these calls block and can
// be slow.
- if (const int numEligibleDisplays = numDisplaysWithOffloadPresentSupport(args);
- numEligibleDisplays > 1) {
- // Leave the last eligible display on the main thread, which will
- // allow it to run concurrently without an extra thread hop.
- int numToOffload = numEligibleDisplays - 1;
- for (auto& output : args.outputs) {
- if (output->supportsOffloadPresent()) {
- output->offloadPresentNextFrame();
- if (--numToOffload == 0) {
- break;
- }
- }
- }
- }
+ offloadOutputs(args.outputs);
ui::DisplayVector<ftl::Future<std::monostate>> presentFutures;
for (const auto& output : args.outputs) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 13b6307aea..a18397d8ba 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <android-base/properties.h>
+#include <common/FlagManager.h>
#include <compositionengine/impl/planner/Flattener.h>
#include <compositionengine/impl/planner/LayerState.h>
@@ -50,8 +51,19 @@ bool isSameStack(const std::vector<const LayerState*>& incomingLayers,
for (size_t i = 0; i < incomingLayers.size(); i++) {
// Checking the IDs here is very strict, but we do this as otherwise we may mistakenly try
// to access destroyed OutputLayers later on.
- if (incomingLayers[i]->getId() != existingLayers[i]->getId() ||
- incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
+ if (incomingLayers[i]->getId() != existingLayers[i]->getId()) {
+ return false;
+ }
+
+ // Do not unflatten if source crop is only moved.
+ if (FlagManager::getInstance().cache_if_source_crop_layer_only_moved() &&
+ incomingLayers[i]->isSourceCropSizeEqual(*(existingLayers[i])) &&
+ incomingLayers[i]->getDifferingFields(*(existingLayers[i])) ==
+ LayerStateField::SourceCrop) {
+ continue;
+ }
+
+ if (incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
return false;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index 8dab6ce61b..0e3fdbb0dc 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -76,6 +76,11 @@ size_t LayerState::getHash() const {
return hash;
}
+bool LayerState::isSourceCropSizeEqual(const LayerState& other) const {
+ return mSourceCrop.get().getWidth() == other.mSourceCrop.get().getWidth() &&
+ mSourceCrop.get().getHeight() == other.mSourceCrop.get().getHeight();
+}
+
ftl::Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
ftl::Flags<LayerStateField> differences;
auto myFields = getNonUniqueFields();
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index a451ab2b77..602dd236f7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/CompositionEngine.h>
@@ -29,6 +31,8 @@
#include <variant>
+using namespace com::android::graphics::surfaceflinger;
+
namespace android::compositionengine {
namespace {
@@ -110,11 +114,9 @@ TEST_F(CompositionEnginePresentTest, worksAsExpected) {
EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _));
EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _));
- if (FlagManager::getInstance().multithreaded_present()) {
- EXPECT_CALL(*mOutput1, getDisplayId()).WillOnce(Return(std::nullopt));
- EXPECT_CALL(*mOutput2, getDisplayId()).WillOnce(Return(std::nullopt));
- EXPECT_CALL(*mOutput3, getDisplayId()).WillOnce(Return(std::nullopt));
- }
+ // All of mOutput<i> are StrictMocks. If the flag is true, it will introduce
+ // calls to getDisplayId, which are not relevant to this test.
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, false);
// The last step is to actually present each output.
EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs)))
@@ -272,5 +274,164 @@ TEST_F(CompositionTestPreComposition,
EXPECT_TRUE(mEngine.needsAnotherUpdate());
}
+struct CompositionEngineOffloadTest : public testing::Test {
+ impl::CompositionEngine mEngine;
+ CompositionRefreshArgs mRefreshArgs;
+
+ std::shared_ptr<mock::Output> mDisplay1{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Output> mDisplay2{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Output> mVirtualDisplay{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Output> mHalVirtualDisplay{std::make_shared<StrictMock<mock::Output>>()};
+
+ static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(123u);
+ static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(234u);
+ static constexpr GpuVirtualDisplayId kGpuVirtualDisplayId{789u};
+ static constexpr HalVirtualDisplayId kHalVirtualDisplayId{456u};
+
+ void SetUp() override {
+ EXPECT_CALL(*mDisplay1, getDisplayId)
+ .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId1)));
+ EXPECT_CALL(*mDisplay2, getDisplayId)
+ .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId2)));
+ EXPECT_CALL(*mVirtualDisplay, getDisplayId)
+ .WillRepeatedly(Return(std::make_optional<DisplayId>(kGpuVirtualDisplayId)));
+ EXPECT_CALL(*mHalVirtualDisplay, getDisplayId)
+ .WillRepeatedly(Return(std::make_optional<DisplayId>(kHalVirtualDisplayId)));
+ }
+
+ void setOutputs(std::initializer_list<std::shared_ptr<mock::Output>> outputs) {
+ for (auto& output : outputs) {
+ // If we call mEngine.present, prepare and present will be called on all the
+ // outputs in mRefreshArgs, but that's not the interesting part of the test.
+ EXPECT_CALL(*output, prepare(Ref(mRefreshArgs), _)).Times(1);
+ EXPECT_CALL(*output, present(Ref(mRefreshArgs)))
+ .WillOnce(Return(ftl::yield<std::monostate>({})));
+
+ mRefreshArgs.outputs.push_back(std::move(output));
+ }
+ }
+};
+
+TEST_F(CompositionEngineOffloadTest, basic) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, dependsOnSupport) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(false));
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).Times(0);
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, dependsOnSupport2) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, dependsOnFlag) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).Times(0);
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).Times(0);
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, false);
+ setOutputs({mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, oneDisplay) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).Times(0);
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, virtualDisplay) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mVirtualDisplay, supportsOffloadPresent).Times(0);
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mVirtualDisplay, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2, mVirtualDisplay});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, virtualDisplay2) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mVirtualDisplay, supportsOffloadPresent).Times(0);
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mVirtualDisplay, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mVirtualDisplay});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, halVirtual) {
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mHalVirtualDisplay, supportsOffloadPresent).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mHalVirtualDisplay, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mHalVirtualDisplay});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, ordering) {
+ EXPECT_CALL(*mVirtualDisplay, supportsOffloadPresent).Times(0);
+ EXPECT_CALL(*mHalVirtualDisplay, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillOnce(Return(true));
+
+ EXPECT_CALL(*mVirtualDisplay, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mHalVirtualDisplay, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mVirtualDisplay, mHalVirtualDisplay, mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index d9318af371..763b998b3d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <common/include/common/test/FlagUtils.h>
+#include "com_android_graphics_surfaceflinger_flags.h"
+
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/planner/CachedSet.h>
#include <compositionengine/impl/planner/Flattener.h>
@@ -239,6 +242,30 @@ TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) {
expectAllLayersFlattened(layers);
}
+TEST_F(FlattenerTest, unflattenLayers_onlySourceCropMoved) {
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::
+ cache_if_source_crop_layer_only_moved,
+ true);
+
+ auto& layerState1 = mTestLayers[0]->layerState;
+ auto& layerState2 = mTestLayers[1]->layerState;
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ };
+
+ initializeFlattener(layers);
+
+ mTestLayers[0]->outputLayerCompositionState.sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+ mTestLayers[1]->outputLayerCompositionState.sourceCrop = FloatRect{8.f, 16.f, 108.f, 116.f};
+
+ // only source crop is moved, so no flatten
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
+}
+
TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
auto& layerState1 = mTestLayers[0]->layerState;
auto& layerState2 = mTestLayers[1]->layerState;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index cc2f6c7cb3..369021995c 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -78,6 +78,7 @@ using AidlDisplayConnectionType =
using AidlColorTransform = aidl::android::hardware::graphics::common::ColorTransform;
using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace;
+using AidlDisplayHotplugEvent = aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using AidlFRect = aidl::android::hardware::graphics::common::FRect;
using AidlRect = aidl::android::hardware::graphics::common::Rect;
using AidlTransform = aidl::android::hardware::graphics::common::Transform;
@@ -174,9 +175,9 @@ public:
AidlIComposerCallbackWrapper(HWC2::ComposerCallback& callback) : mCallback(callback) {}
::ndk::ScopedAStatus onHotplug(int64_t in_display, bool in_connected) override {
- const auto connection = in_connected ? V2_4::IComposerCallback::Connection::CONNECTED
- : V2_4::IComposerCallback::Connection::DISCONNECTED;
- mCallback.onComposerHalHotplug(translate<Display>(in_display), connection);
+ const auto event = in_connected ? AidlDisplayHotplugEvent::CONNECTED
+ : AidlDisplayHotplugEvent::DISCONNECTED;
+ mCallback.onComposerHalHotplugEvent(translate<Display>(in_display), event);
return ::ndk::ScopedAStatus::ok();
}
@@ -216,6 +217,12 @@ public:
return ::ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display,
+ AidlDisplayHotplugEvent event) override {
+ mCallback.onComposerHalHotplugEvent(translate<Display>(in_display), event);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
private:
HWC2::ComposerCallback& mCallback;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e7f807f553..29fe38008d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -38,6 +38,7 @@
#include "Hal.h"
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
@@ -64,15 +65,16 @@ class Layer;
namespace hal = android::hardware::graphics::composer::hal;
+using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
// Implement this interface to receive hardware composer events.
//
// These callback functions will generally be called on a hwbinder thread, but
-// when first registering the callback the onComposerHalHotplug() function will
-// immediately be called on the thread calling registerCallback().
+// when first registering the callback the onComposerHalHotplugEvent() function
+// will immediately be called on the thread calling registerCallback().
struct ComposerCallback {
- virtual void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) = 0;
+ virtual void onComposerHalHotplugEvent(hal::HWDisplayId, DisplayHotplugEvent) = 0;
virtual void onComposerHalRefresh(hal::HWDisplayId) = 0;
virtual void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp,
std::optional<hal::VsyncPeriodNanos>) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 26c0d67af9..10df216b02 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -545,6 +545,7 @@ status_t HWComposer::getDeviceCompositionChanges(
}
}
+ ATRACE_FORMAT("NextFrameInterval %d_Hz", frameInterval.getIntValue());
if (canSkipValidate) {
sp<Fence> outPresentFence = Fence::NO_FENCE;
uint32_t state = UINT32_MAX;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 20f7548bea..31c2833229 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -20,6 +20,7 @@
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h>
#include <aidl/android/hardware/graphics/common/Hdr.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -58,6 +59,7 @@ using Connection = IComposerCallback::Connection;
using ContentType = IComposerClient::ContentType;
using Capability = IComposer::Capability;
using ClientTargetProperty = IComposerClient::ClientTargetProperty;
+using DisplayHotplugEvent = aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using DisplayRequest = IComposerClient::DisplayRequest;
using DisplayType = IComposerClient::DisplayType;
using HWConfigId = V2_1::Config;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 1e7c6da592..ed52b9583c 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -25,6 +25,7 @@
#include "HidlComposerHal.h"
#include <SurfaceFlingerProperties.h>
+#include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h>
#include <android/binder_manager.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <hidl/HidlTransportSupport.h>
@@ -38,6 +39,7 @@
#include <algorithm>
#include <cinttypes>
+using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using aidl::android::hardware::graphics::common::HdrConversionCapability;
using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::Capability;
@@ -64,8 +66,13 @@ public:
ComposerCallbackBridge(ComposerCallback& callback, bool vsyncSwitchingSupported)
: mCallback(callback), mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
+ // For code sharing purposes, `ComposerCallback` (implemented by SurfaceFlinger)
+ // replaced `onComposerHalHotplug` with `onComposerHalHotplugEvent` by converting
+ // from HIDL's connection into an AIDL DisplayHotplugEvent.
Return<void> onHotplug(Display display, Connection connection) override {
- mCallback.onComposerHalHotplug(display, connection);
+ const auto event = connection == Connection::CONNECTED ? DisplayHotplugEvent::CONNECTED
+ : DisplayHotplugEvent::DISCONNECTED;
+ mCallback.onComposerHalHotplugEvent(display, event);
return Void();
}
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index e55cd3ea42..55b395b458 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -18,41 +18,26 @@
#include "DisplayDevice.h"
namespace android {
-namespace {
-
-RenderArea::RotationFlags applyDeviceOrientation(bool useIdentityTransform,
- const DisplayDevice& display) {
- if (!useIdentityTransform) {
- return RenderArea::RotationFlags::ROT_0;
- }
-
- return ui::Transform::toRotationFlags(display.getOrientation());
-}
-
-} // namespace
std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak,
const Rect& sourceCrop, ui::Size reqSize,
ui::Dataspace reqDataSpace,
- bool useIdentityTransform,
bool hintForSeamlessTransition,
bool allowSecureLayers) {
if (auto display = displayWeak.promote()) {
// Using new to access a private constructor.
return std::unique_ptr<DisplayRenderArea>(
new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
- useIdentityTransform, hintForSeamlessTransition,
- allowSecureLayers));
+ hintForSeamlessTransition, allowSecureLayers));
}
return nullptr;
}
DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool useIdentityTransform, bool hintForSeamlessTransition,
- bool allowSecureLayers)
+ bool hintForSeamlessTransition, bool allowSecureLayers)
: RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, hintForSeamlessTransition,
- allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)),
+ allowSecureLayers),
mDisplay(std::move(display)),
mSourceCrop(sourceCrop) {}
@@ -73,17 +58,7 @@ Rect DisplayRenderArea::getSourceCrop() const {
if (mSourceCrop.isEmpty()) {
return mDisplay->getLayerStackSpaceRect();
}
-
- // Correct for the orientation when the screen capture request contained
- // useIdentityTransform. This will cause the rotation flag to be non 0 since
- // it needs to rotate based on the screen orientation to allow the screenshot
- // to be taken in the ROT_0 orientation
- const auto flags = getRotationFlags();
- int width = mDisplay->getLayerStackSpaceRect().getWidth();
- int height = mDisplay->getLayerStackSpaceRect().getHeight();
- ui::Transform rotation;
- rotation.set(flags, width, height);
- return rotation.transform(mSourceCrop);
+ return mSourceCrop;
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
index 9a4981c881..4555a9ed66 100644
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -29,7 +29,6 @@ class DisplayRenderArea : public RenderArea {
public:
static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace,
- bool useIdentityTransform,
bool hintForSeamlessTransition,
bool allowSecureLayers = true);
@@ -40,8 +39,7 @@ public:
private:
DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
- ui::Dataspace, bool useIdentityTransform, bool hintForSeamlessTransition,
- bool allowSecureLayers = true);
+ ui::Dataspace, bool hintForSeamlessTransition, bool allowSecureLayers = true);
const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 9dc3938322..803299cf6f 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -280,6 +280,19 @@ int32_t jankTypeBitmaskToProto(int32_t jankType) {
return protoJank;
}
+FrameTimelineEvent::JankSeverityType toProto(JankSeverityType jankSeverityType) {
+ switch (jankSeverityType) {
+ case JankSeverityType::Unknown:
+ return FrameTimelineEvent::SEVERITY_UNKNOWN;
+ case JankSeverityType::None:
+ return FrameTimelineEvent::SEVERITY_NONE;
+ case JankSeverityType::Partial:
+ return FrameTimelineEvent::SEVERITY_PARTIAL;
+ case JankSeverityType::Full:
+ return FrameTimelineEvent::SEVERITY_FULL;
+ }
+}
+
// Returns the smallest timestamp from the set of predictions and actuals.
nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions,
TimelineItem actuals) {
@@ -389,6 +402,15 @@ std::optional<int32_t> SurfaceFrame::getJankType() const {
return mJankType;
}
+std::optional<JankSeverityType> SurfaceFrame::getJankSeverityType() const {
+ std::scoped_lock lock(mMutex);
+ if (mActuals.presentTime == 0) {
+ // Frame hasn't been presented yet.
+ return std::nullopt;
+ }
+ return mJankSeverityType;
+}
+
nsecs_t SurfaceFrame::getBaseTime() const {
std::scoped_lock lock(mMutex);
return getMinTime(mPredictionState, mPredictions, mActuals);
@@ -505,10 +527,11 @@ std::string SurfaceFrame::miniDump() const {
}
void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
- nsecs_t& deadlineDelta) {
+ Fps displayFrameRenderRate, nsecs_t& deadlineDelta) {
if (mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
// Cannot do any classification for invalid present time.
mJankType = JankType::Unknown;
+ mJankSeverityType = JankSeverityType::Unknown;
deadlineDelta = -1;
return;
}
@@ -519,6 +542,7 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
// reasonable app, so prediction expire would mean a huge scheduling delay.
mJankType = mPresentState != PresentState::Presented ? JankType::Dropped
: JankType::AppDeadlineMissed;
+ mJankSeverityType = JankSeverityType::Unknown;
deadlineDelta = -1;
return;
}
@@ -543,6 +567,11 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
: FramePresentMetadata::EarlyPresent;
+ // Jank that is missing by less than the render rate period is classified as partial jank,
+ // otherwise it is a full jank.
+ mJankSeverityType = std::abs(presentDelta) < displayFrameRenderRate.getPeriodNsecs()
+ ? JankSeverityType::Partial
+ : JankSeverityType::Full;
} else {
mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
}
@@ -613,6 +642,7 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
mJankType = JankType::Dropped;
// Since frame was not presented, lets drop any present value
mActuals.presentTime = 0;
+ mJankSeverityType = JankSeverityType::Unknown;
}
}
@@ -625,7 +655,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
mActuals.presentTime = presentTime;
nsecs_t deadlineDelta = 0;
- classifyJankLocked(displayFrameJankType, refreshRate, deadlineDelta);
+ classifyJankLocked(displayFrameJankType, refreshRate, displayFrameRenderRate, deadlineDelta);
if (mPredictionState != PredictionState::None) {
// Only update janky frames if the app used vsync predictions
@@ -718,6 +748,7 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffse
actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
actualSurfaceFrameStartEvent->set_prediction_type(toProto(mPredictionState));
actualSurfaceFrameStartEvent->set_is_buffer(mIsBuffer);
+ actualSurfaceFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
});
// Actual timeline end
@@ -910,6 +941,7 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
// Cannot do jank classification with expired predictions or invalid signal times. Set the
// deltas to 0 as both negative and positive deltas are used as real values.
mJankType = JankType::Unknown;
+ mJankSeverityType = JankSeverityType::Unknown;
deadlineDelta = 0;
deltaToVsync = 0;
if (!presentTimeValid) {
@@ -941,6 +973,11 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
: FramePresentMetadata::EarlyPresent;
+ // Jank that is missing by less than the render rate period is classified as partial jank,
+ // otherwise it is a full jank.
+ mJankSeverityType = std::abs(presentDelta) < mRenderRate.getPeriodNsecs()
+ ? JankSeverityType::Partial
+ : JankSeverityType::Full;
} else {
mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
}
@@ -1119,6 +1156,7 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs
actualDisplayFrameStartEvent->set_prediction_type(toProto(PredictionState::Valid));
actualDisplayFrameStartEvent->set_present_type(FrameTimelineEvent::PRESENT_DROPPED);
actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(JankType::Dropped));
+ actualDisplayFrameStartEvent->set_jank_severity_type(toProto(JankSeverityType::None));
});
// Actual timeline end
@@ -1160,6 +1198,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid,
actualDisplayFrameStartEvent->set_gpu_composition(mGpuFence != FenceTime::NO_FENCE);
actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState));
+ actualDisplayFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
});
// Actual timeline end
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 6598e218fd..b5047a3467 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -168,6 +168,7 @@ public:
// Returns std::nullopt if the frame hasn't been classified yet.
// Used by both SF and FrameTimeline.
std::optional<int32_t> getJankType() const;
+ std::optional<JankSeverityType> getJankSeverityType() const;
// Functions called by SF
int64_t getToken() const { return mToken; };
@@ -232,7 +233,7 @@ private:
void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
- nsecs_t& deadlineDelta) REQUIRES(mMutex);
+ Fps displayFrameRenderRate, nsecs_t& deadlineDelta) REQUIRES(mMutex);
const int64_t mToken;
const int32_t mInputEventId;
@@ -252,6 +253,8 @@ private:
mutable std::mutex mMutex;
// Bitmask for the type of jank
int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
+ // Enum for the severity of jank
+ JankSeverityType mJankSeverityType GUARDED_BY(mMutex) = JankSeverityType::None;
// Indicates if this frame was composited by the GPU or not
bool mGpuComposition GUARDED_BY(mMutex) = false;
// Refresh rate for this frame.
@@ -404,6 +407,7 @@ public:
FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; };
FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; };
int32_t getJankType() const { return mJankType; }
+ JankSeverityType getJankSeverityType() const { return mJankSeverityType; }
const std::vector<std::shared_ptr<SurfaceFrame>>& getSurfaceFrames() const {
return mSurfaceFrames;
}
@@ -435,6 +439,8 @@ public:
PredictionState mPredictionState = PredictionState::None;
// Bitmask for the type of jank
int32_t mJankType = JankType::None;
+ // Enum for the severity of jank
+ JankSeverityType mJankSeverityType = JankSeverityType::None;
// A valid gpu fence indicates that the DisplayFrame was composited by the GPU
std::shared_ptr<FenceTime> mGpuFence = FenceTime::NO_FENCE;
// Enum for the type of present
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 743cbf3cb1..a92cc03831 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -814,9 +814,12 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a
RequestedLayerState::Changes::Hierarchy) ||
snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
RequestedLayerState::Changes::Hierarchy)) {
- bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy ==
+ const bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy ==
scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren;
- if (!requested.requestedFrameRate.isValid() || shouldOverrideChildren) {
+ const bool propagationAllowed = parentSnapshot.frameRateSelectionStrategy !=
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self;
+ if ((!requested.requestedFrameRate.isValid() && propagationAllowed) ||
+ shouldOverrideChildren) {
snapshot.inheritedFrameRate = parentSnapshot.inheritedFrameRate;
} else {
snapshot.inheritedFrameRate = requested.requestedFrameRate;
@@ -828,12 +831,15 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionStrategyChanged) {
- const auto strategy = scheduler::LayerInfo::convertFrameRateSelectionStrategy(
- requested.frameRateSelectionStrategy);
- snapshot.frameRateSelectionStrategy =
- strategy == scheduler::LayerInfo::FrameRateSelectionStrategy::Self
- ? parentSnapshot.frameRateSelectionStrategy
- : strategy;
+ if (parentSnapshot.frameRateSelectionStrategy ==
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren) {
+ snapshot.frameRateSelectionStrategy =
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren;
+ } else {
+ const auto strategy = scheduler::LayerInfo::convertFrameRateSelectionStrategy(
+ requested.frameRateSelectionStrategy);
+ snapshot.frameRateSelectionStrategy = strategy;
+ }
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) {
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index b1a18aefb5..21172ca015 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -125,7 +125,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args)
frameRateCategory = static_cast<int8_t>(FrameRateCategory::Default);
frameRateCategorySmoothSwitchOnly = false;
frameRateSelectionStrategy =
- static_cast<int8_t>(scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ static_cast<int8_t>(scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
dataspace = ui::Dataspace::V0_SRGB;
gameMode = gui::GameMode::Unsupported;
requestedFrameRate = {};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9195b57886..949a161a35 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -193,7 +193,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args)
mDrawingState.dropInputMode = gui::DropInputMode::NONE;
mDrawingState.dimmingEnabled = true;
mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
- mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Self;
+ mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Propagate;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
// Set an invalid color so there is no color fill.
@@ -1273,14 +1273,15 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overr
auto now = systemTime();
*transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate, now);
- // The frame rate is propagated to the children
+ // The frame rate is propagated to the children by default, but some properties may override it.
bool childrenHaveFrameRate = false;
+ const bool overrideChildrenFrameRate = overrideChildren || shouldOverrideChildrenFrameRate();
+ const bool canPropagateFrameRate = shouldPropagateFrameRate() || overrideChildrenFrameRate;
for (const sp<Layer>& child : mCurrentChildren) {
childrenHaveFrameRate |=
- child->propagateFrameRateForLayerTree(frameRate,
- overrideChildren ||
- shouldOverrideChildrenFrameRate(),
- transactionNeeded);
+ child->propagateFrameRateForLayerTree(canPropagateFrameRate ? frameRate
+ : FrameRate(),
+ overrideChildrenFrameRate, transactionNeeded);
}
// If we don't have a valid frame rate specification, but the children do, we set this
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 28168c3f65..c772e0ea1b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1178,6 +1178,10 @@ private:
FrameRateSelectionStrategy::OverrideChildren;
}
+ bool shouldPropagateFrameRate() const {
+ return getDrawingState().frameRateSelectionStrategy != FrameRateSelectionStrategy::Self;
+ }
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
// a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 8f658d5a09..6db39f143f 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -276,13 +276,11 @@ void RegionSamplingThread::captureSample() {
}
const Rect sampledBounds = sampleRegion.bounds();
- constexpr bool kUseIdentityTransform = false;
constexpr bool kHintForSeamlessTransition = false;
SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
- ui::Dataspace::V0_SRGB, kUseIdentityTransform,
- kHintForSeamlessTransition);
+ ui::Dataspace::V0_SRGB, kHintForSeamlessTransition);
});
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 71b85bd3b2..5de148e3bd 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -18,20 +18,16 @@ class DisplayDevice;
// physical render area.
class RenderArea {
public:
- using RotationFlags = ui::Transform::RotationFlags;
-
enum class CaptureFill {CLEAR, OPAQUE};
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
- bool hintForSeamlessTransition, bool allowSecureLayers = false,
- RotationFlags rotation = ui::Transform::ROT_0)
+ bool hintForSeamlessTransition, bool allowSecureLayers = false)
: mAllowSecureLayers(allowSecureLayers),
mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
- mRotationFlags(rotation),
mHintForSeamlessTransition(hintForSeamlessTransition) {}
static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
@@ -72,9 +68,6 @@ public:
// on the display).
virtual Rect getSourceCrop() const = 0;
- // Returns the rotation of the source crop and the layers.
- RotationFlags getRotationFlags() const { return mRotationFlags; }
-
// Returns the size of the physical render area.
int getReqWidth() const { return mReqSize.width; }
int getReqHeight() const { return mReqSize.height; }
@@ -103,7 +96,6 @@ private:
const ui::Size mReqSize;
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
- const RotationFlags mRotationFlags;
const bool mHintForSeamlessTransition;
};
diff --git a/services/surfaceflinger/Scheduler/FrameRateCompatibility.h b/services/surfaceflinger/Scheduler/FrameRateCompatibility.h
index 405c982494..d8c408f485 100644
--- a/services/surfaceflinger/Scheduler/FrameRateCompatibility.h
+++ b/services/surfaceflinger/Scheduler/FrameRateCompatibility.h
@@ -29,6 +29,8 @@ enum class FrameRateCompatibility {
ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
// content properly. Any other value will result in a pull down.
+ Gte, // Layer needs greater than or equal to the frame rate.
+
NoVote, // Layer doesn't have any requirements for the refresh rate and
// should not be considered when the display refresh rate is determined.
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index d309adccf8..9c003026ea 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -278,6 +278,8 @@ void LayerHistory::partitionLayers(nsecs_t now) {
return LayerVoteType::NoVote;
case Layer::FrameRateCompatibility::Exact:
return LayerVoteType::ExplicitExact;
+ case Layer::FrameRateCompatibility::Gte:
+ return LayerVoteType::ExplicitGte;
}
}();
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index bf3a7bc8b7..97fca395b4 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -276,17 +276,16 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(const RefreshRateSe
if (const auto averageFrameTime = calculateAverageFrameTime()) {
const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
- const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
- if (refreshRateConsistent) {
- const auto knownRefreshRate = selector.findClosestKnownFrameRate(refreshRate);
+ const auto closestKnownRefreshRate = mRefreshRateHistory.add(refreshRate, now, selector);
+ if (closestKnownRefreshRate.isValid()) {
using fps_approx_ops::operator!=;
// To avoid oscillation, use the last calculated refresh rate if it is close enough.
if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
MARGIN &&
- mLastRefreshRate.reported != knownRefreshRate) {
+ mLastRefreshRate.reported != closestKnownRefreshRate) {
mLastRefreshRate.calculated = refreshRate;
- mLastRefreshRate.reported = knownRefreshRate;
+ mLastRefreshRate.reported = closestKnownRefreshRate;
}
ALOGV("%s %s rounded to nearest known frame rate %s", mName.c_str(),
@@ -432,7 +431,8 @@ void LayerInfo::RefreshRateHistory::clear() {
mRefreshRates.clear();
}
-bool LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now) {
+Fps LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now,
+ const RefreshRateSelector& selector) {
mRefreshRates.push_back({refreshRate, now});
while (mRefreshRates.size() >= HISTORY_SIZE ||
now - mRefreshRates.front().timestamp > HISTORY_DURATION.count()) {
@@ -447,11 +447,11 @@ bool LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now) {
ATRACE_INT(mHeuristicTraceTagData->average.c_str(), refreshRate.getIntValue());
}
- return isConsistent();
+ return selectRefreshRate(selector);
}
-bool LayerInfo::RefreshRateHistory::isConsistent() const {
- if (mRefreshRates.empty()) return true;
+Fps LayerInfo::RefreshRateHistory::selectRefreshRate(const RefreshRateSelector& selector) const {
+ if (mRefreshRates.empty()) return Fps();
const auto [min, max] =
std::minmax_element(mRefreshRates.begin(), mRefreshRates.end(),
@@ -459,8 +459,19 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const {
return isStrictlyLess(lhs.refreshRate, rhs.refreshRate);
});
- const bool consistent =
- max->refreshRate.getValue() - min->refreshRate.getValue() < MARGIN_CONSISTENT_FPS;
+ const auto maxClosestRate = selector.findClosestKnownFrameRate(max->refreshRate);
+ const bool consistent = [&](Fps maxFps, Fps minFps) {
+ if (FlagManager::getInstance().use_known_refresh_rate_for_fps_consistency()) {
+ if (maxFps.getValue() - minFps.getValue() <
+ MARGIN_CONSISTENT_FPS_FOR_CLOSEST_REFRESH_RATE) {
+ const auto minClosestRate = selector.findClosestKnownFrameRate(minFps);
+ using fps_approx_ops::operator==;
+ return maxClosestRate == minClosestRate;
+ }
+ return false;
+ }
+ return maxFps.getValue() - minFps.getValue() < MARGIN_CONSISTENT_FPS;
+ }(max->refreshRate, min->refreshRate);
if (CC_UNLIKELY(sTraceEnabled)) {
if (!mHeuristicTraceTagData.has_value()) {
@@ -472,7 +483,7 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const {
ATRACE_INT(mHeuristicTraceTagData->consistent.c_str(), consistent);
}
- return consistent;
+ return consistent ? maxClosestRate : Fps();
}
FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) {
@@ -485,6 +496,8 @@ FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compati
return FrameRateCompatibility::Exact;
case ANATIVEWINDOW_FRAME_RATE_MIN:
return FrameRateCompatibility::Min;
+ case ANATIVEWINDOW_FRAME_RATE_GTE:
+ return FrameRateCompatibility::Gte;
case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
return FrameRateCompatibility::NoVote;
default:
@@ -526,10 +539,12 @@ FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) {
LayerInfo::FrameRateSelectionStrategy LayerInfo::convertFrameRateSelectionStrategy(
int8_t strategy) {
switch (strategy) {
- case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF:
- return FrameRateSelectionStrategy::Self;
+ case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_PROPAGATE:
+ return FrameRateSelectionStrategy::Propagate;
case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN:
return FrameRateSelectionStrategy::OverrideChildren;
+ case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF:
+ return FrameRateSelectionStrategy::Self;
default:
LOG_ALWAYS_FATAL("Invalid frame rate selection strategy value %d", strategy);
return FrameRateSelectionStrategy::Self;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index d24fc33491..50bb83dc29 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -81,10 +81,11 @@ public:
using RefreshRateVotes = ftl::SmallVector<LayerInfo::LayerVote, 2>;
enum class FrameRateSelectionStrategy {
- Self,
+ Propagate,
OverrideChildren,
+ Self,
- ftl_last = OverrideChildren
+ ftl_last = Self
};
// Encapsulates the frame rate specifications of the layer. This information will be used
@@ -264,8 +265,8 @@ private:
// Clears History
void clear();
- // Adds a new refresh rate and returns true if it is consistent
- bool add(Fps refreshRate, nsecs_t now);
+ // Adds a new refresh rate and returns valid refresh rate if it is consistent enough
+ Fps add(Fps refreshRate, nsecs_t now, const RefreshRateSelector&);
private:
friend class LayerHistoryTest;
@@ -285,13 +286,14 @@ private:
std::string average;
};
- bool isConsistent() const;
+ Fps selectRefreshRate(const RefreshRateSelector&) const;
HeuristicTraceTagData makeHeuristicTraceTagData() const;
const std::string mName;
mutable std::optional<HeuristicTraceTagData> mHeuristicTraceTagData;
std::deque<RefreshRateData> mRefreshRates;
static constexpr float MARGIN_CONSISTENT_FPS = 1.0;
+ static constexpr float MARGIN_CONSISTENT_FPS_FOR_CLOSEST_REFRESH_RATE = 5.0;
};
// Represents whether we were able to determine either layer is frequent or infrequent
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 6a7063e40f..e06221a43d 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -332,6 +332,15 @@ float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const Layer
return calculateNonExactMatchingDefaultLayerScoreLocked(displayPeriod, layerPeriod);
}
+ if (layer.vote == LayerVoteType::ExplicitGte) {
+ using fps_approx_ops::operator>=;
+ if (refreshRate >= layer.desiredRefreshRate) {
+ return 1.0f;
+ } else {
+ return calculateDistanceScoreLocked(layer.desiredRefreshRate, refreshRate);
+ }
+ }
+
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
using fps_approx_ops::operator<;
@@ -390,13 +399,20 @@ float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const Layer
return 0;
}
-float RefreshRateSelector::calculateDistanceScoreFromMax(Fps refreshRate) const {
- const auto& maxFps = mAppRequestFrameRates.back().fps;
- const float ratio = refreshRate.getValue() / maxFps.getValue();
- // Use ratio^2 to get a lower score the more we get further from peak
+float RefreshRateSelector::calculateDistanceScoreLocked(Fps referenceRate, Fps refreshRate) const {
+ using fps_approx_ops::operator>=;
+ const float ratio = referenceRate >= refreshRate
+ ? refreshRate.getValue() / referenceRate.getValue()
+ : referenceRate.getValue() / refreshRate.getValue();
+ // Use ratio^2 to get a lower score the more we get further from the reference rate.
return ratio * ratio;
}
+float RefreshRateSelector::calculateDistanceScoreFromMaxLocked(Fps refreshRate) const {
+ const auto& maxFps = mAppRequestFrameRates.back().fps;
+ return calculateDistanceScoreLocked(maxFps, refreshRate);
+}
+
float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
bool isSeamlessSwitch) const {
// Slightly prefer seamless switches.
@@ -421,7 +437,7 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
- return calculateDistanceScoreFromMax(refreshRate);
+ return calculateDistanceScoreFromMaxLocked(refreshRate);
}
if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -489,6 +505,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
int explicitDefaultVoteLayers = 0;
int explicitExactOrMultipleVoteLayers = 0;
int explicitExact = 0;
+ int explicitGteLayers = 0;
int explicitCategoryVoteLayers = 0;
int seamedFocusedLayers = 0;
int categorySmoothSwitchOnlyLayers = 0;
@@ -513,6 +530,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
case LayerVoteType::ExplicitExact:
explicitExact++;
break;
+ case LayerVoteType::ExplicitGte:
+ explicitGteLayers++;
+ break;
case LayerVoteType::ExplicitCategory:
explicitCategoryVoteLayers++;
if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
@@ -535,7 +555,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
}
const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 ||
- explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0 ||
+ explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0 || explicitGteLayers > 0 ||
explicitCategoryVoteLayers > 0;
const Policy* policy = getCurrentPolicyLocked();
@@ -688,6 +708,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi
case LayerVoteType::Max:
case LayerVoteType::ExplicitDefault:
case LayerVoteType::ExplicitExact:
+ case LayerVoteType::ExplicitGte:
case LayerVoteType::ExplicitCategory:
return false;
}
@@ -1081,7 +1102,7 @@ auto RefreshRateSelector::rankFrameRates(std::optional<int> anchorGroupOpt,
return;
}
- float score = calculateDistanceScoreFromMax(frameRateMode.fps);
+ float score = calculateDistanceScoreFromMaxLocked(frameRateMode.fps);
if (ascending) {
score = 1.0f / score;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 40e9a8310f..9f6a29cbc9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -149,6 +149,7 @@ public:
// ExactOrMultiple compatibility
ExplicitExact, // Specific refresh rate that was provided by the app with
// Exact compatibility
+ ExplicitGte, // Greater than or equal to frame rate provided by the app
ExplicitCategory, // Specific frame rate category was provided by the app
ftl_last = ExplicitCategory
@@ -460,7 +461,11 @@ private:
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
// Returns the refresh rate score as a ratio to max refresh rate, which has a score of 1.
- float calculateDistanceScoreFromMax(Fps refreshRate) const REQUIRES(mLock);
+ float calculateDistanceScoreFromMaxLocked(Fps refreshRate) const REQUIRES(mLock);
+
+ // Returns the refresh rate score based on its distance from the reference rate.
+ float calculateDistanceScoreLocked(Fps referenceRate, Fps refreshRate) const REQUIRES(mLock);
+
// calculates a score for a layer. Used to determine the display refresh rate
// and the frame rate override for certains applications.
float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6610f948a7..6eea7f1aa1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -510,8 +510,11 @@ void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
- for (const auto& [id, _] : mDisplays) {
- resyncToHardwareVsyncLocked(id, allowToEnable);
+ for (const auto& [id, display] : mDisplays) {
+ if (display.powerMode != hal::PowerMode::OFF ||
+ !FlagManager::getInstance().multithreaded_present()) {
+ resyncToHardwareVsyncLocked(id, allowToEnable);
+ }
}
}
@@ -579,6 +582,24 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) {
display.schedulePtr->getTracker().setRenderRate(renderFrameRate);
}
+Fps Scheduler::getNextFrameInterval(PhysicalDisplayId id,
+ TimePoint currentExpectedPresentTime) const {
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ const auto displayOpt = mDisplays.get(id);
+ if (!displayOpt) {
+ ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
+ return Fps{};
+ }
+ const Display& display = *displayOpt;
+ const nsecs_t threshold =
+ display.selectorPtr->getActiveMode().modePtr->getVsyncRate().getPeriodNsecs() / 2;
+ const nsecs_t nextVsyncTime = display.schedulePtr->getTracker().nextAnticipatedVSyncTimeFrom(
+ currentExpectedPresentTime.ns() + threshold);
+ return Fps::fromPeriodNsecs(nextVsyncTime - currentExpectedPresentTime.ns());
+}
+
void Scheduler::resync() {
static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 8a76436fda..65470480af 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -313,6 +313,9 @@ public:
return pacesetterSelectorPtr()->getActiveMode().fps;
}
+ Fps getNextFrameInterval(PhysicalDisplayId, TimePoint currentExpectedPresentTime) const
+ EXCLUDES(mDisplayLock);
+
// Returns the framerate of the layer with the given sequence ID
float getLayerFramerate(nsecs_t now, int32_t id) const {
return mLayerHistory.getLayerFramerate(now, id);
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index ef9b457fc9..57b0d5e0ea 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -16,6 +16,7 @@
#include "ScreenCaptureOutput.h"
#include "ScreenCaptureRenderSurface.h"
+#include "ui/Rotation.h"
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayColorProfileCreationArgs.h>
@@ -24,24 +25,6 @@
namespace android {
-namespace {
-
-ui::Size getDisplaySize(ui::Rotation orientation, const Rect& sourceCrop) {
- if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
- return {sourceCrop.getHeight(), sourceCrop.getWidth()};
- }
- return {sourceCrop.getWidth(), sourceCrop.getHeight()};
-}
-
-Rect getOrientedDisplaySpaceRect(ui::Rotation orientation, int reqWidth, int reqHeight) {
- if (orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270) {
- return {reqHeight, reqWidth};
- }
- return {reqWidth, reqHeight};
-}
-
-} // namespace
-
std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) {
std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated<
ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
@@ -62,11 +45,10 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp
.Build()));
const Rect& sourceCrop = args.renderArea.getSourceCrop();
- const ui::Rotation orientation = ui::Transform::toRotation(args.renderArea.getRotationFlags());
- output->setDisplaySize(getDisplaySize(orientation, sourceCrop));
+ const ui::Rotation orientation = ui::ROTATION_0;
+ output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()});
output->setProjection(orientation, sourceCrop,
- getOrientedDisplaySpaceRect(orientation, args.renderArea.getReqWidth(),
- args.renderArea.getReqHeight()));
+ {args.renderArea.getReqWidth(), args.renderArea.getReqHeight()});
{
std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput";
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6e6229ac4c..85c16b716d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2101,15 +2101,28 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t
}
}
-void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
- hal::Connection connection) {
- {
- std::lock_guard<std::mutex> lock(mHotplugMutex);
- mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
+void SurfaceFlinger::onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId,
+ DisplayHotplugEvent event) {
+ if (event == DisplayHotplugEvent::CONNECTED || event == DisplayHotplugEvent::DISCONNECTED) {
+ hal::Connection connection = (event == DisplayHotplugEvent::CONNECTED)
+ ? hal::Connection::CONNECTED
+ : hal::Connection::DISCONNECTED;
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
+ }
+
+ if (mScheduler) {
+ mScheduler->scheduleConfigure();
+ }
+
+ return;
}
- if (mScheduler) {
- mScheduler->scheduleConfigure();
+ if (FlagManager::getInstance().hotplug2()) {
+ ALOGD("SurfaceFlinger got hotplug event=%d", static_cast<int32_t>(event));
+ // TODO(b/311403559): use enum type instead of int
+ mScheduler->onHotplugConnectionError(mAppConnectionHandle, static_cast<int32_t>(event));
}
}
@@ -2619,10 +2632,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
- if (display->getId() == pacesetterId) {
- // TODO(b/255601557) Update frameInterval per display
- refreshArgs.frameInterval = display->refreshRateSelector().getActiveMode().fps;
- }
}
mPowerAdvisor->setDisplays(displayIds);
@@ -2687,8 +2696,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
pacesetterTarget.previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
}
+ const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime();
+ // TODO(b/255601557) Update frameInterval per display
+ refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime);
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
- refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns();
+ refreshArgs.expectedPresentTime = expectedPresentTime.ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
// Store the present time just before calling to the composition engine so we could notify
@@ -7058,7 +7070,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
const hal::HWDisplayId hwcId =
(Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId());
- onComposerHalHotplug(hwcId, hal::Connection::CONNECTED);
+ onComposerHalHotplugEvent(hwcId, DisplayHotplugEvent::CONNECTED);
return NO_ERROR;
}
// Modify the max number of display frames stored within FrameTimeline
@@ -7560,8 +7572,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, args.dataspace,
- args.useIdentityTransform, args.hintForSeamlessTransition,
- args.captureSecureLayers);
+ args.hintForSeamlessTransition, args.captureSecureLayers);
});
GetLayerSnapshotsFunction getLayerSnapshots;
@@ -7614,7 +7625,6 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, Rect(), size, args.dataspace,
- false /* useIdentityTransform */,
args.hintForSeamlessTransition,
false /* captureSecureLayers */);
});
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e90f8feb6e..788fe73519 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -106,6 +106,7 @@
#include <vector>
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h>
#include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h>
#include "Client.h"
@@ -130,6 +131,7 @@ class FrameTracer;
class ScreenCapturer;
class WindowInfosListenerInvoker;
+using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using frontend::TransactionHandler;
using gui::CaptureArgs;
@@ -629,7 +631,7 @@ private:
// HWC2::ComposerCallback overrides:
void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp,
std::optional<hal::VsyncPeriodNanos>) override;
- void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) override;
+ void onComposerHalHotplugEvent(hal::HWDisplayId, DisplayHotplugEvent) override;
void onComposerHalRefresh(hal::HWDisplayId) override;
void onComposerHalVsyncPeriodTimingChanged(hal::HWDisplayId,
const hal::VsyncPeriodChangeTimeline&) override;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index e2a1498003..a5822323ce 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -121,6 +121,8 @@ void FlagManager::dump(std::string& result) const {
DUMP_READ_ONLY_FLAG(hdcp_level_hal);
DUMP_READ_ONLY_FLAG(multithreaded_present);
DUMP_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace);
+ DUMP_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency);
+ DUMP_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -190,6 +192,9 @@ FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "")
FLAG_MANAGER_READ_ONLY_FLAG(hdcp_level_hal, "")
FLAG_MANAGER_READ_ONLY_FLAG(multithreaded_present, "debug.sf.multithreaded_present")
FLAG_MANAGER_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace, "")
+FLAG_MANAGER_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency, "")
+FLAG_MANAGER_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved,
+ "debug.sf.cache_source_crop_only_moved")
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 9aabbb9870..15ca345502 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -60,6 +60,8 @@ public:
bool hdcp_level_hal() const;
bool multithreaded_present() const;
bool add_sf_skipped_frames_to_trace() const;
+ bool use_known_refresh_rate_for_fps_consistency() const;
+ bool cache_if_source_crop_layer_only_moved() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
index 1a951b34ac..b2dc20e216 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
@@ -41,6 +41,7 @@ class SurfaceComposerClient;
namespace android::hardware::graphics::composer::hal {
+using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -52,7 +53,9 @@ public:
: mCallback(callback), mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
Return<void> onHotplug(HWDisplayId display, Connection connection) override {
- mCallback->onComposerHalHotplug(display, connection);
+ const auto event = connection == Connection::CONNECTED ? DisplayHotplugEvent::CONNECTED
+ : DisplayHotplugEvent::DISCONNECTED;
+ mCallback->onComposerHalHotplugEvent(display, event);
return Void();
}
@@ -94,7 +97,7 @@ private:
struct TestHWC2ComposerCallback : public HWC2::ComposerCallback {
virtual ~TestHWC2ComposerCallback() = default;
- void onComposerHalHotplug(HWDisplayId, Connection){};
+ void onComposerHalHotplugEvent(HWDisplayId, DisplayHotplugEvent) {}
void onComposerHalRefresh(HWDisplayId) {}
void onComposerHalVsync(HWDisplayId, int64_t, std::optional<VsyncPeriodNanos>) {}
void onComposerHalVsyncPeriodTimingChanged(HWDisplayId, const VsyncPeriodChangeTimeline&) {}
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index 71c59b26f8..3fb763ec12 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -84,3 +84,19 @@ flag {
description: "enable refresh rate indicator on the external display"
bug: "301647974"
}
+
+flag {
+ name: "use_known_refresh_rate_for_fps_consistency"
+ namespace: "core_graphics"
+ description: "Whether to use the closest known refresh rate to determine the fps consistency."
+ bug: "299201319"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "cache_if_source_crop_layer_only_moved"
+ namespace: "core_graphics"
+ description: "do not flatten layers if source crop is only moved"
+ bug: "305718400"
+ is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 0a951d49e3..aeff5a530d 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -56,60 +56,44 @@ protected:
ASSERT_EQ(res, NO_ERROR);
}
- void testSetAllowGroupSwitching(bool allowGroupSwitching);
+ void testSetDesiredDisplayModeSpecs(bool allowGroupSwitching = false) {
+ ui::DynamicDisplayInfo info;
+ status_t res =
+ SurfaceComposerClient::getDynamicDisplayInfoFromId(static_cast<int64_t>(mDisplayId),
+ &info);
+ const auto& modes = info.supportedDisplayModes;
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_GT(modes.size(), 0);
+ for (const auto& mode : modes) {
+ gui::DisplayModeSpecs setSpecs;
+ setSpecs.defaultMode = mode.id;
+ setSpecs.allowGroupSwitching = allowGroupSwitching;
+ setSpecs.primaryRanges.physical.min = mode.peakRefreshRate;
+ setSpecs.primaryRanges.physical.max = mode.peakRefreshRate;
+ setSpecs.primaryRanges.render = setSpecs.primaryRanges.physical;
+ setSpecs.appRequestRanges = setSpecs.primaryRanges;
+
+ res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, setSpecs);
+ ASSERT_EQ(res, NO_ERROR);
+ gui::DisplayModeSpecs getSpecs;
+ res = SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken, &getSpecs);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(setSpecs, getSpecs);
+ }
+ }
sp<IBinder> mDisplayToken;
uint64_t mDisplayId;
};
TEST_F(RefreshRateRangeTest, setAllConfigs) {
- ui::DynamicDisplayInfo info;
- status_t res =
- SurfaceComposerClient::getDynamicDisplayInfoFromId(static_cast<int64_t>(mDisplayId),
- &info);
- const auto& modes = info.supportedDisplayModes;
- ASSERT_EQ(res, NO_ERROR);
- ASSERT_GT(modes.size(), 0);
-
- gui::DisplayModeSpecs setSpecs;
- setSpecs.allowGroupSwitching = false;
- for (size_t i = 0; i < modes.size(); i++) {
- setSpecs.defaultMode = modes[i].id;
- setSpecs.primaryRanges.physical.min = modes[i].peakRefreshRate;
- setSpecs.primaryRanges.physical.max = modes[i].peakRefreshRate;
- setSpecs.primaryRanges.render = setSpecs.primaryRanges.physical;
- setSpecs.appRequestRanges = setSpecs.primaryRanges;
- res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, setSpecs);
- ASSERT_EQ(res, NO_ERROR);
-
- gui::DisplayModeSpecs getSpecs;
- res = SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken, &getSpecs);
- ASSERT_EQ(res, NO_ERROR);
- ASSERT_EQ(setSpecs, getSpecs);
- }
-}
-
-void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) {
- gui::DisplayModeSpecs setSpecs;
- setSpecs.defaultMode = 0;
- setSpecs.allowGroupSwitching = allowGroupSwitching;
- setSpecs.primaryRanges.physical.min = 0;
- setSpecs.primaryRanges.physical.max = 90;
- setSpecs.primaryRanges.render = setSpecs.primaryRanges.physical;
- setSpecs.appRequestRanges = setSpecs.primaryRanges;
-
- status_t res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, setSpecs);
- ASSERT_EQ(res, NO_ERROR);
- gui::DisplayModeSpecs getSpecs;
- res = SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken, &getSpecs);
- ASSERT_EQ(res, NO_ERROR);
- ASSERT_EQ(setSpecs, getSpecs);
+ testSetDesiredDisplayModeSpecs();
}
TEST_F(RefreshRateRangeTest, setAllowGroupSwitching) {
- testSetAllowGroupSwitching(true);
- testSetAllowGroupSwitching(false);
- testSetAllowGroupSwitching(true);
+ testSetDesiredDisplayModeSpecs(/*allowGroupSwitching=*/true);
+ testSetDesiredDisplayModeSpecs(/*allowGroupSwitching=*/false);
+ testSetDesiredDisplayModeSpecs(/*allowGroupSwitching=*/true);
}
} // namespace android
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 21813700a2..15a98df275 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -38,7 +38,6 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) {
args.displayToken = sp<BBinder>::make();
args.width = 10;
args.height = 20;
- args.useIdentityTransform = true;
args.grayscale = true;
Parcel p;
@@ -56,7 +55,6 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) {
ASSERT_EQ(args.displayToken, args2.displayToken);
ASSERT_EQ(args.width, args2.width);
ASSERT_EQ(args.height, args2.height);
- ASSERT_EQ(args.useIdentityTransform, args2.useIdentityTransform);
ASSERT_EQ(args.grayscale, args2.grayscale);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
index 3873b0c076..bd80d88392 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -43,7 +43,8 @@ public:
PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
- mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
+ mFlinger.onComposerHalHotplugEvent(PrimaryDisplayVariant::HWC_DISPLAY_ID,
+ DisplayHotplugEvent::CONNECTED);
mFlinger.configureAndCommit();
mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
index 20ea0c080a..5c742d7360 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
@@ -49,6 +49,7 @@ protected:
const FrameRate FRAME_RATE_VOTE1 = FrameRate(11_Hz, FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_VOTE2 = FrameRate(22_Hz, FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_VOTE3 = FrameRate(33_Hz, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_DEFAULT = FrameRate(Fps(), FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
FrameRateSelectionStrategyTest();
@@ -102,7 +103,7 @@ TEST_P(FrameRateSelectionStrategyTest, SetAndGet) {
layer->getDrawingState().frameRateSelectionStrategy);
}
-TEST_P(FrameRateSelectionStrategyTest, SetChildAndGetParent) {
+TEST_P(FrameRateSelectionStrategyTest, SetChildOverrideChildren) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
const auto& layerFactory = GetParam();
@@ -116,17 +117,17 @@ TEST_P(FrameRateSelectionStrategyTest, SetChildAndGetParent) {
child2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
commitTransaction();
EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
parent->getDrawingState().frameRateSelectionStrategy);
EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
child1->getDrawingState().frameRateSelectionStrategy);
EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
child2->getDrawingState().frameRateSelectionStrategy);
}
-TEST_P(FrameRateSelectionStrategyTest, SetParentAndGet) {
+TEST_P(FrameRateSelectionStrategyTest, SetParentOverrideChildren) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
const auto& layerFactory = GetParam();
@@ -137,7 +138,6 @@ TEST_P(FrameRateSelectionStrategyTest, SetParentAndGet) {
addChild(layer2, layer3);
layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
- layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
@@ -151,20 +151,72 @@ TEST_P(FrameRateSelectionStrategyTest, SetParentAndGet) {
EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
layer2->getDrawingState().frameRateSelectionStrategy);
EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
layer3->getDrawingState().frameRateSelectionStrategy);
- layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Self);
+ layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Propagate);
commitTransaction();
EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
layer1->getDrawingState().frameRateSelectionStrategy);
EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
layer2->getDrawingState().frameRateSelectionStrategy);
EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+}
+
+TEST_P(FrameRateSelectionStrategyTest, OverrideChildrenAndSelf) {
+ EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
+
+ const auto& layerFactory = GetParam();
+ auto layer1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto layer2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto layer3 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ addChild(layer1, layer2);
+ addChild(layer2, layer3);
+
+ layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
+ layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
+ layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Self);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_DEFAULT, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+
+ layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer2->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+
+ layer1->setFrameRate(FRAME_RATE_DEFAULT.vote);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_TREE, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
layer3->getDrawingState().frameRateSelectionStrategy);
}
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 9dd14317ef..ddc3967c40 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -41,6 +41,7 @@ using ProtoActualSurfaceFrameStart = perfetto::protos::FrameTimelineEvent_Actual
using ProtoFrameEnd = perfetto::protos::FrameTimelineEvent_FrameEnd;
using ProtoPresentType = perfetto::protos::FrameTimelineEvent_PresentType;
using ProtoJankType = perfetto::protos::FrameTimelineEvent_JankType;
+using ProtoJankSeverityType = perfetto::protos::FrameTimelineEvent_JankSeverityType;
using ProtoPredictionType = perfetto::protos::FrameTimelineEvent_PredictionType;
namespace android::frametimeline {
@@ -335,7 +336,9 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 42);
EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 42);
EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+ EXPECT_NE(surfaceFrame1->getJankSeverityType(), std::nullopt);
EXPECT_NE(surfaceFrame2->getJankType(), std::nullopt);
+ EXPECT_NE(surfaceFrame2->getJankSeverityType(), std::nullopt);
}
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
@@ -493,8 +496,10 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) {
auto displayFrame0 = getDisplayFrame(0);
EXPECT_EQ(displayFrame0->getActuals().presentTime, 59);
EXPECT_EQ(displayFrame0->getJankType(), JankType::Unknown | JankType::DisplayHAL);
+ EXPECT_EQ(displayFrame0->getJankSeverityType(), JankSeverityType::Unknown);
EXPECT_EQ(surfaceFrame1->getActuals().presentTime, -1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Unknown);
}
// Tests related to TimeStats
@@ -604,6 +609,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
presentFence1->signalForTest(90);
mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
@@ -633,6 +639,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
mFrameTimeline->setSfPresent(86, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
@@ -662,6 +669,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
@@ -691,6 +699,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
@@ -721,6 +730,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
mFrameTimeline->setSfPresent(86, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::BufferStuffing);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
@@ -752,6 +762,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
mFrameTimeline->setSfPresent(86, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPresentsSurfaceFrame) {
@@ -788,12 +799,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres
auto displayFrame = getDisplayFrame(0);
EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Unknown);
EXPECT_EQ(displayFrame->getFrameStartMetadata(), FrameStartMetadata::UnknownStart);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
EXPECT_EQ(surfaceFrame1->getActuals().presentTime, 90);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown | JankType::AppDeadlineMissed);
+ EXPECT_EQ(surfaceFrame1->getJankSeverityType(), JankSeverityType::Full);
}
/*
@@ -920,7 +933,8 @@ ProtoExpectedDisplayFrameStart createProtoExpectedDisplayFrameStart(int64_t cook
ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart(
int64_t cookie, int64_t token, pid_t pid, ProtoPresentType presentType, bool onTimeFinish,
- bool gpuComposition, ProtoJankType jankType, ProtoPredictionType predictionType) {
+ bool gpuComposition, ProtoJankType jankType, ProtoJankSeverityType jankSeverityType,
+ ProtoPredictionType predictionType) {
ProtoActualDisplayFrameStart proto;
proto.set_cookie(cookie);
proto.set_token(token);
@@ -929,6 +943,7 @@ ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart(
proto.set_on_time_finish(onTimeFinish);
proto.set_gpu_composition(gpuComposition);
proto.set_jank_type(jankType);
+ proto.set_jank_severity_type(jankSeverityType);
proto.set_prediction_type(predictionType);
return proto;
}
@@ -949,7 +964,8 @@ ProtoExpectedSurfaceFrameStart createProtoExpectedSurfaceFrameStart(int64_t cook
ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart(
int64_t cookie, int64_t token, int64_t displayFrameToken, pid_t pid, std::string layerName,
ProtoPresentType presentType, bool onTimeFinish, bool gpuComposition,
- ProtoJankType jankType, ProtoPredictionType predictionType, bool isBuffer) {
+ ProtoJankType jankType, ProtoJankSeverityType jankSeverityType,
+ ProtoPredictionType predictionType, bool isBuffer) {
ProtoActualSurfaceFrameStart proto;
proto.set_cookie(cookie);
proto.set_token(token);
@@ -960,6 +976,7 @@ ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart(
proto.set_on_time_finish(onTimeFinish);
proto.set_gpu_composition(gpuComposition);
proto.set_jank_type(jankType);
+ proto.set_jank_severity_type(jankSeverityType);
proto.set_prediction_type(predictionType);
proto.set_is_buffer(isBuffer);
return proto;
@@ -1002,6 +1019,8 @@ void validateTraceEvent(const ProtoActualDisplayFrameStart& received,
EXPECT_EQ(received.gpu_composition(), source.gpu_composition());
ASSERT_TRUE(received.has_jank_type());
EXPECT_EQ(received.jank_type(), source.jank_type());
+ ASSERT_TRUE(received.has_jank_severity_type());
+ EXPECT_EQ(received.jank_severity_type(), source.jank_severity_type());
ASSERT_TRUE(received.has_prediction_type());
EXPECT_EQ(received.prediction_type(), source.prediction_type());
}
@@ -1049,6 +1068,8 @@ void validateTraceEvent(const ProtoActualSurfaceFrameStart& received,
EXPECT_EQ(received.gpu_composition(), source.gpu_composition());
ASSERT_TRUE(received.has_jank_type());
EXPECT_EQ(received.jank_type(), source.jank_type());
+ ASSERT_TRUE(received.has_jank_severity_type());
+ EXPECT_EQ(received.jank_severity_type(), source.jank_severity_type());
ASSERT_TRUE(received.has_prediction_type());
EXPECT_EQ(received.prediction_type(), source.prediction_type());
ASSERT_TRUE(received.has_is_buffer());
@@ -1116,6 +1137,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrameSkipped) {
createProtoActualDisplayFrameStart(traceCookie + 9, 0, kSurfaceFlingerPid,
FrameTimelineEvent::PRESENT_DROPPED, true, false,
FrameTimelineEvent::JANK_DROPPED,
+ FrameTimelineEvent::SEVERITY_NONE,
FrameTimelineEvent::PREDICTION_VALID);
auto protoSkippedActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 9);
@@ -1176,6 +1198,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
kSurfaceFlingerPid,
FrameTimelineEvent::PRESENT_ON_TIME, true, false,
FrameTimelineEvent::JANK_NONE,
+ FrameTimelineEvent::SEVERITY_NONE,
FrameTimelineEvent::PREDICTION_VALID);
auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 2);
@@ -1255,6 +1278,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte
kSurfaceFlingerPid,
FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
false, FrameTimelineEvent::JANK_UNKNOWN,
+ FrameTimelineEvent::SEVERITY_UNKNOWN,
FrameTimelineEvent::PREDICTION_EXPIRED);
auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
@@ -1330,6 +1354,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
displayFrameToken1, sPidOne, sLayerNameOne,
FrameTimelineEvent::PRESENT_DROPPED, true, false,
FrameTimelineEvent::JANK_DROPPED,
+ FrameTimelineEvent::SEVERITY_UNKNOWN,
FrameTimelineEvent::PREDICTION_VALID, true);
auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2);
@@ -1342,6 +1367,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
displayFrameToken1, sPidOne, sLayerNameOne,
FrameTimelineEvent::PRESENT_ON_TIME, true, false,
FrameTimelineEvent::JANK_NONE,
+ FrameTimelineEvent::SEVERITY_NONE,
FrameTimelineEvent::PREDICTION_VALID, true);
auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4);
@@ -1488,6 +1514,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline
displayFrameToken, sPidOne, sLayerNameOne,
FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
false, FrameTimelineEvent::JANK_APP_DEADLINE_MISSED,
+ FrameTimelineEvent::SEVERITY_UNKNOWN,
FrameTimelineEvent::PREDICTION_EXPIRED, true);
auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
@@ -1565,6 +1592,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced
displayFrameToken, sPidOne, sLayerNameOne,
FrameTimelineEvent::PRESENT_DROPPED, false, false,
FrameTimelineEvent::JANK_DROPPED,
+ FrameTimelineEvent::SEVERITY_UNKNOWN,
FrameTimelineEvent::PREDICTION_EXPIRED, true);
auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
@@ -1643,6 +1671,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::None);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
@@ -1669,6 +1698,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Partial);
// Fences for the second frame haven't been flushed yet, so it should be 0
auto displayFrame2 = getDisplayFrame(1);
@@ -1682,6 +1712,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
@@ -1708,6 +1739,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::DisplayHAL);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Partial);
// Fences for the second frame haven't been flushed yet, so it should be 0
auto displayFrame2 = getDisplayFrame(1);
@@ -1722,6 +1754,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) {
@@ -1744,6 +1777,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent)
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
@@ -1789,6 +1823,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+ EXPECT_EQ(displayFrame0->getJankSeverityType(), JankSeverityType::Full);
// case 3 - cpu time = 86 - 82 = 4, vsync period = 30
mFrameTimeline->setSfWakeUp(sfToken3, 106, RR_30, RR_30);
@@ -1803,6 +1838,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::Full);
// case 4 - cpu time = 86 - 82 = 4, vsync period = 30
mFrameTimeline->setSfWakeUp(sfToken4, 120, RR_30, RR_30);
@@ -1817,6 +1853,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerStuffing);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::Full);
addEmptyDisplayFrame();
@@ -1825,6 +1862,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame3->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame3->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame3->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+ EXPECT_EQ(displayFrame3->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
@@ -1877,12 +1915,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::Partial);
actuals1 = presentedSurfaceFrame1.getActuals();
EXPECT_EQ(actuals1.presentTime, 30);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Partial);
// Fences for the second frame haven't been flushed yet, so it should be 0
presentFence2->signalForTest(65);
@@ -1905,12 +1945,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::Partial);
actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 65);
EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::PredictionError);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
@@ -1963,12 +2005,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::DisplayHAL);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::Partial);
actuals1 = presentedSurfaceFrame1.getActuals();
EXPECT_EQ(actuals1.presentTime, 50);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::DisplayHAL);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Partial);
// Fences for the second frame haven't been flushed yet, so it should be 0
presentFence2->signalForTest(86);
@@ -1991,12 +2035,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::Full);
actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 86);
EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::PredictionError);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
@@ -2033,12 +2079,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent)
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::None);
actuals1 = presentedSurfaceFrame1.getActuals();
EXPECT_EQ(actuals1.presentTime, 50);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::Unknown);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) {
@@ -2095,12 +2143,14 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::None);
actuals1 = presentedSurfaceFrame1.getActuals();
EXPECT_EQ(actuals1.presentTime, 40);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Partial);
// Fences for the second frame haven't been flushed yet, so it should be 0
presentFence2->signalForTest(60);
@@ -2115,6 +2165,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::Partial);
actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 60);
@@ -2122,6 +2173,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent)
EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame2.getJankType(),
JankType::SurfaceFlingerCpuDeadlineMissed | JankType::AppDeadlineMissed);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankSeverityType(), JankSeverityType::Partial);
}
TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
@@ -2181,10 +2233,12 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::None);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Full);
// Fences for the second frame haven't been flushed yet, so it should be 0
EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
@@ -2201,11 +2255,13 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::None);
EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame2.getJankType(),
JankType::AppDeadlineMissed | JankType::BufferStuffing);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffing) {
@@ -2266,10 +2322,12 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame1->getJankSeverityType(), JankSeverityType::None);
EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankSeverityType(), JankSeverityType::Full);
// Fences for the second frame haven't been flushed yet, so it should be 0
EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
@@ -2286,10 +2344,12 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::None);
EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_GpuAndCpuMiss) {
@@ -2317,6 +2377,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_G
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Full);
// Case 2: No GPU fence so it will not use GPU composition.
mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_30, RR_30);
@@ -2334,6 +2395,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_G
EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+ EXPECT_EQ(displayFrame2->getJankSeverityType(), JankSeverityType::Full);
}
TEST_F(FrameTimelineTest, jankClassification_presentFenceError) {
@@ -2364,6 +2426,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentFenceError) {
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown | JankType::DisplayHAL);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Unknown);
}
{
auto displayFrame = getDisplayFrame(1);
@@ -2371,6 +2434,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentFenceError) {
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown | JankType::DisplayHAL);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::Unknown);
}
{
auto displayFrame = getDisplayFrame(2);
@@ -2378,6 +2442,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentFenceError) {
EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
EXPECT_EQ(displayFrame->getJankType(), JankType::None);
+ EXPECT_EQ(displayFrame->getJankSeverityType(), JankSeverityType::None);
}
}
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 4a2273182e..d3ce4f2b90 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -57,6 +57,7 @@ using namespace std::chrono_literals;
using Hwc2::Config;
+using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using hal::IComposerClient;
using ::testing::_;
@@ -555,7 +556,8 @@ TEST_F(HWComposerTest, notifyExpectedPresentRenderRateChanged) {
}
struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> {
- MOCK_METHOD2(onComposerHalHotplug, void(hal::HWDisplayId, hal::Connection));
+ MOCK_METHOD(void, onComposerHalHotplugEvent, (hal::HWDisplayId, DisplayHotplugEvent),
+ (override));
MOCK_METHOD1(onComposerHalRefresh, void(hal::HWDisplayId));
MOCK_METHOD3(onComposerHalVsync,
void(hal::HWDisplayId, int64_t timestamp, std::optional<hal::VsyncPeriodNanos>));
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index c1059d7733..787fa1c5e4 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -768,6 +768,7 @@ TEST_F(LayerHistoryIntegrationTest, heuristicLayer60_30Hz) {
}
TEST_F(LayerHistoryIntegrationTest, heuristicLayerNotOscillating) {
+ SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, false);
auto layer = createLegacyAndFrontedEndLayer(1);
nsecs_t time = systemTime();
@@ -779,6 +780,20 @@ TEST_F(LayerHistoryIntegrationTest, heuristicLayerNotOscillating) {
recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
}
+TEST_F(LayerHistoryIntegrationTest, heuristicLayerNotOscillating_useKnownRefreshRate) {
+ SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, true);
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ nsecs_t time = systemTime();
+
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+}
+
TEST_F(LayerHistoryIntegrationTest, smallDirtyLayer) {
auto layer = createLegacyAndFrontedEndLayer(1);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index c24d397e31..b88ef563c3 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1169,6 +1169,24 @@ TEST_F(LayerHistoryTest, heuristicLayer60_30Hz) {
}
TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
+ SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, false);
+
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+}
+
+TEST_F(LayerHistoryTest, heuristicLayerNotOscillating_useKnownRefreshRate) {
+ SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, true);
+
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
@@ -1179,6 +1197,7 @@ TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
}
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 16143e3a7f..040a3bfb3e 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -814,24 +814,24 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategy) {
EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.type,
scheduler::FrameRateCompatibility::NoVote);
EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate));
EXPECT_FALSE(getSnapshot({.id = 121})->frameRate.vote.rate.isValid());
EXPECT_EQ(getSnapshot({.id = 121})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_EQ(getSnapshot({.id = 121})->frameRate.vote.type,
scheduler::FrameRateCompatibility::Default);
EXPECT_TRUE(getSnapshot({.id = 121})->changes.test(RequestedLayerState::Changes::FrameRate));
EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 123.f);
EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.rate.getValue(), 123.f);
EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
}
@@ -904,12 +904,12 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithCategory) {
scheduler::FrameRateCompatibility::NoVote);
EXPECT_EQ(getSnapshot({.id = 12})->frameRate.category, FrameRateCategory::Default);
EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate));
EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid());
EXPECT_EQ(getSnapshot({.id = 121})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_EQ(getSnapshot({.id = 121})->frameRate.category, FrameRateCategory::Default);
EXPECT_EQ(getSnapshot({.id = 121})->frameRate.vote.type,
scheduler::FrameRateCompatibility::Default);
@@ -917,17 +917,105 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithCategory) {
EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 123.f);
EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Default);
EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.rate.getValue(), 123.f);
EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionStrategy,
- scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Default);
EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
}
+TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithOverrideChildrenAndSelf) {
+ // ROOT
+ // ├── 1
+ // │ ├── 11 (frame rate set to 11.f with strategy Self)
+ // │ │ └── 111 (frame rate is not inherited)
+ // │ ├── 12 (frame rate set to 244.f)
+ // │ │ ├── 121
+ // │ │ └── 122 (strategy OverrideChildren and inherits frame rate 244.f)
+ // │ │ └── 1221 (frame rate set to 123.f but should be overridden by layer 122)
+ // │ └── 13
+ // └── 2
+ setFrameRate(11, 11.f, 0, 0);
+ setFrameRateSelectionStrategy(11, 2 /* Self */);
+ setFrameRate(12, 244.f, 0, 0);
+ setFrameRateSelectionStrategy(122, 1 /* OverrideChildren */);
+ setFrameRate(1221, 123.f, 0, 0);
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ // verify parent 1 gets no vote
+ EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
+ scheduler::FrameRateCompatibility::NoVote);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 11.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 11 does does not propagate its framerate to 111.
+ EXPECT_FALSE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
+ EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 12 and all descendants (121, 122, 1221) get the requested vote
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
+ EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 121})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 121})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Propagate);
+ EXPECT_TRUE(getSnapshot({.id = 121})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // ROOT
+ // ├── 1 (frame rate set to 1.f with strategy OverrideChildren)
+ // │ ├── 11 (frame rate set to 11.f with strategy Self, but overridden by 1)
+ // │ │ └── 111 (frame rate inherited from 11 due to override from 1)
+ // ⋮ ⋮
+ setFrameRate(1, 1.f, 0, 0);
+ setFrameRateSelectionStrategy(1, 1 /* OverrideChildren */);
+ setFrameRate(11, 11.f, 0, 0);
+ setFrameRateSelectionStrategy(11, 2 /* Self */);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
+ scheduler::FrameRateCompatibility::Default);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 11 does does not propagate its framerate to 111.
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+}
+
TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) {
setRoundedCorners(1, 42.f);
setRoundedCorners(2, 42.f);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index a9567b2881..0cacf810c0 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1150,6 +1150,75 @@ TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) {
EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr);
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitGte) {
+ auto selector = createSelector(makeModes(kMode30, kMode60, kMode90, kMode120), kModeId120);
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 25_Hz;
+ lr1.name = "25Hz ExplicitGte";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 91_Hz;
+ lr1.name = "91Hz ExplicitGte";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 30_Hz;
+ lr2.name = "30Hz ExplicitDefault";
+ EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 30_Hz;
+ lr2.name = "30Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60_Hz;
+ lr2.name = "60Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90_Hz;
+ lr2.name = "90Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr);
+
+ lr1.vote = LayerVoteType::ExplicitGte;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitGte";
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.name = "120Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr);
+}
+
TEST_P(RefreshRateSelectorTest, getMaxRefreshRatesByPolicy) {
// The kModes_30_60_90 contains two kMode72_G1, kMode120_G1 which are from the
// different group.
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 8a8f771a1d..e515895a1a 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <common/test/FlagUtils.h>
#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -23,6 +24,7 @@
#include "Scheduler/EventThread.h"
#include "Scheduler/RefreshRateSelector.h"
+#include "Scheduler/VSyncPredictor.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
@@ -32,11 +34,15 @@
#include <FrontEnd/LayerHierarchy.h>
+#include <com_android_graphics_surfaceflinger_flags.h>
#include "FpsOps.h"
+using namespace com::android::graphics::surfaceflinger;
+
namespace android::scheduler {
using android::mock::createDisplayMode;
+using android::mock::createVrrDisplayMode;
using testing::_;
using testing::Return;
@@ -548,6 +554,139 @@ TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
EXPECT_EQ(makeVsyncIds(VsyncId(44), true), compositor.vsyncIds.composite);
}
+TEST_F(SchedulerTest, nextFrameIntervalTest) {
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ static constexpr size_t kHistorySize = 10;
+ static constexpr size_t kMinimumSamplesForPrediction = 6;
+ static constexpr size_t kOutlierTolerancePercent = 25;
+ const auto refreshRate = Fps::fromPeriodNsecs(500);
+ auto frameRate = Fps::fromPeriodNsecs(1000);
+
+ const ftl::NonNull<DisplayModePtr> kMode = ftl::as_non_null(
+ createVrrDisplayMode(DisplayModeId(0), refreshRate,
+ hal::VrrConfig{.minFrameIntervalNs = static_cast<int32_t>(
+ frameRate.getPeriodNsecs())}));
+ std::shared_ptr<VSyncPredictor> vrrTracker =
+ std::make_shared<VSyncPredictor>(kMode, kHistorySize, kMinimumSamplesForPrediction,
+ kOutlierTolerancePercent, mVsyncTrackerCallback);
+ std::shared_ptr<RefreshRateSelector> vrrSelectorPtr =
+ std::make_shared<RefreshRateSelector>(makeModes(kMode), kMode->getId());
+ TestableScheduler scheduler{std::make_unique<android::mock::VsyncController>(),
+ vrrTracker,
+ vrrSelectorPtr,
+ sp<VsyncModulator>::make(VsyncConfigSet{}),
+ mSchedulerCallback,
+ mVsyncTrackerCallback};
+
+ scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
+ vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
+ scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate);
+ vrrTracker->addVsyncTimestamp(0);
+
+ // Next frame at refresh rate as no previous frame
+ EXPECT_EQ(refreshRate,
+ scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(0)));
+
+ EXPECT_EQ(Fps::fromPeriodNsecs(1000),
+ scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(),
+ TimePoint::fromNs(500)));
+ EXPECT_EQ(Fps::fromPeriodNsecs(1000),
+ scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(),
+ TimePoint::fromNs(1500)));
+
+ // Change render rate
+ frameRate = Fps::fromPeriodNsecs(2000);
+ vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
+ scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate);
+
+ EXPECT_EQ(Fps::fromPeriodNsecs(2000),
+ scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(),
+ TimePoint::fromNs(2500)));
+ EXPECT_EQ(Fps::fromPeriodNsecs(2000),
+ scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(),
+ TimePoint::fromNs(4500)));
+}
+
+TEST_F(SchedulerTest, resyncAllToHardwareVsync) FTL_FAKE_GUARD(kMainThreadContext) {
+ // resyncAllToHardwareVsync will result in requesting hardware VSYNC on both displays, since
+ // they are both on.
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, true)).Times(1);
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId2, true)).Times(1);
+
+ mScheduler->registerDisplay(kDisplayId2,
+ std::make_shared<RefreshRateSelector>(kDisplay2Modes,
+ kDisplay2Mode60->getId()));
+ mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
+ mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON);
+
+ static constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(kDisplayId1, kDisallow);
+ mScheduler->disableHardwareVsync(kDisplayId2, kDisallow);
+
+ static constexpr bool kAllowToEnable = true;
+ mScheduler->resyncAllToHardwareVsync(kAllowToEnable);
+}
+
+TEST_F(SchedulerTest, resyncAllDoNotAllow) FTL_FAKE_GUARD(kMainThreadContext) {
+ // Without setting allowToEnable to true, resyncAllToHardwareVsync does not
+ // result in requesting hardware VSYNC.
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, _)).Times(0);
+
+ mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
+
+ static constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(kDisplayId1, kDisallow);
+
+ static constexpr bool kAllowToEnable = false;
+ mScheduler->resyncAllToHardwareVsync(kAllowToEnable);
+}
+
+TEST_F(SchedulerTest, resyncAllSkipsOffDisplays) FTL_FAKE_GUARD(kMainThreadContext) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+
+ // resyncAllToHardwareVsync will result in requesting hardware VSYNC on display 1, which is on,
+ // but not on display 2, which is off.
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, true)).Times(1);
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId2, _)).Times(0);
+
+ mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
+
+ mScheduler->registerDisplay(kDisplayId2,
+ std::make_shared<RefreshRateSelector>(kDisplay2Modes,
+ kDisplay2Mode60->getId()));
+ ASSERT_EQ(hal::PowerMode::OFF, mScheduler->getDisplayPowerMode(kDisplayId2));
+
+ static constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(kDisplayId1, kDisallow);
+ mScheduler->disableHardwareVsync(kDisplayId2, kDisallow);
+
+ static constexpr bool kAllowToEnable = true;
+ mScheduler->resyncAllToHardwareVsync(kAllowToEnable);
+}
+
+TEST_F(SchedulerTest, resyncAllLegacyAppliesToOffDisplays) FTL_FAKE_GUARD(kMainThreadContext) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, false);
+
+ // In the legacy code, prior to the flag, resync applied to OFF displays.
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, true)).Times(1);
+ EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId2, true)).Times(1);
+
+ mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
+
+ mScheduler->registerDisplay(kDisplayId2,
+ std::make_shared<RefreshRateSelector>(kDisplay2Modes,
+ kDisplay2Mode60->getId()));
+ ASSERT_EQ(hal::PowerMode::OFF, mScheduler->getDisplayPowerMode(kDisplayId2));
+
+ static constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(kDisplayId1, kDisallow);
+ mScheduler->disableHardwareVsync(kDisplayId2, kDisallow);
+
+ static constexpr bool kAllowToEnable = true;
+ mScheduler->resyncAllToHardwareVsync(kAllowToEnable);
+}
+
class AttachedChoreographerTest : public SchedulerTest {
protected:
void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps,
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 3558ba6f09..01c0a966eb 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -46,7 +46,8 @@ public:
setupScheduler(selectorPtr);
- mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
+ mFlinger.onComposerHalHotplugEvent(PrimaryDisplayVariant::HWC_DISPLAY_ID,
+ DisplayHotplugEvent::CONNECTED);
mFlinger.configureAndCommit();
auto vsyncController = std::make_unique<mock::VsyncController>();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index 1210d0b472..a270dc91f2 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -27,10 +27,10 @@ TEST_F(HotplugTest, schedulesConfigureToProcessHotplugEvents) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleConfigure()).Times(2);
constexpr HWDisplayId hwcDisplayId1 = 456;
- mFlinger.onComposerHalHotplug(hwcDisplayId1, Connection::CONNECTED);
+ mFlinger.onComposerHalHotplugEvent(hwcDisplayId1, DisplayHotplugEvent::CONNECTED);
constexpr HWDisplayId hwcDisplayId2 = 654;
- mFlinger.onComposerHalHotplug(hwcDisplayId2, Connection::DISCONNECTED);
+ mFlinger.onComposerHalHotplugEvent(hwcDisplayId2, DisplayHotplugEvent::DISCONNECTED);
const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
ASSERT_EQ(2u, pendingEvents.size());
@@ -45,7 +45,7 @@ TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
constexpr HWDisplayId displayId1 = 456;
- mFlinger.onComposerHalHotplug(displayId1, Connection::DISCONNECTED);
+ mFlinger.onComposerHalHotplugEvent(displayId1, DisplayHotplugEvent::DISCONNECTED);
mFlinger.configure();
// The configure stage should consume the hotplug queue and produce a display transaction.
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 8b6f0f1b94..2a1b88e6fa 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -78,10 +78,11 @@ public:
auto refreshRateSelector() { return pacesetterSelectorPtr(); }
- void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
+ void registerDisplay(
+ PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
registerDisplay(displayId, std::move(selectorPtr),
- std::make_unique<mock::VsyncController>(),
- std::make_shared<mock::VSyncTracker>());
+ std::make_unique<mock::VsyncController>(), vsyncTracker);
}
void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
@@ -114,6 +115,15 @@ public:
Scheduler::setPacesetterDisplay(displayId);
}
+ std::optional<hal::PowerMode> getDisplayPowerMode(PhysicalDisplayId id) {
+ ftl::FakeGuard guard1(kMainThreadContext);
+ ftl::FakeGuard guard2(mDisplayLock);
+ return mDisplays.get(id).transform(
+ [](const Display& display) { return display.powerMode; });
+ }
+
+ using Scheduler::resyncAllToHardwareVsync;
+
auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
auto& mutableLayerHistory() { return mLayerHistory; }
auto& mutableAttachedChoreographers() { return mAttachedChoreographers; }
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index cf48c76a5b..0909178777 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -466,8 +466,8 @@ public:
mFlinger->commitTransactionsLocked(transactionFlags);
}
- void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) {
- mFlinger->onComposerHalHotplug(hwcDisplayId, connection);
+ void onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, DisplayHotplugEvent event) {
+ mFlinger->onComposerHalHotplugEvent(hwcDisplayId, event);
}
auto setDisplayStateLocked(const DisplayState& s) {