diff options
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) { |