Merge "TouchpadInputMapper: add timer provider" into main
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 1123d4f..073d0c4 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -757,7 +757,7 @@
binder::Status InstalldNativeService::createAppDataLocked(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return) {
+ int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) {
ENFORCE_UID(AID_SYSTEM);
ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
@@ -767,7 +767,8 @@
const char* pkgname = packageName.c_str();
// Assume invalid inode unless filled in below
- if (_aidl_return != nullptr) *_aidl_return = -1;
+ if (ceDataInode != nullptr) *ceDataInode = -1;
+ if (deDataInode != nullptr) *deDataInode = -1;
int32_t uid = multiuser_get_uid(userId, appId);
@@ -805,12 +806,12 @@
// And return the CE inode of the top-level data directory so we can
// clear contents while CE storage is locked
- if (_aidl_return != nullptr) {
+ if (ceDataInode != nullptr) {
ino_t result;
if (get_path_inode(path, &result) != 0) {
return error("Failed to get_path_inode for " + path);
}
- *_aidl_return = static_cast<uint64_t>(result);
+ *ceDataInode = static_cast<uint64_t>(result);
}
}
if (flags & FLAG_STORAGE_DE) {
@@ -829,6 +830,14 @@
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
}
+
+ if (deDataInode != nullptr) {
+ ino_t result;
+ if (get_path_inode(path, &result) != 0) {
+ return error("Failed to get_path_inode for " + path);
+ }
+ *deDataInode = static_cast<uint64_t>(result);
+ }
}
if (flags & FLAG_STORAGE_SDK) {
@@ -892,14 +901,14 @@
binder::Status InstalldNativeService::createAppData(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return) {
+ int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) {
ENFORCE_UID(AID_SYSTEM);
ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
return createAppDataLocked(uuid, packageName, userId, flags, appId, previousAppId, seInfo,
- targetSdkVersion, _aidl_return);
+ targetSdkVersion, ceDataInode, deDataInode);
}
binder::Status InstalldNativeService::createAppData(
@@ -910,9 +919,12 @@
// Locking is performed depeer in the callstack.
int64_t ceDataInode = -1;
+ int64_t deDataInode = -1;
auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
- args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode);
+ args.previousAppId, args.seInfo, args.targetSdkVersion,
+ &ceDataInode, &deDataInode);
_aidl_return->ceDataInode = ceDataInode;
+ _aidl_return->deDataInode = deDataInode;
_aidl_return->exceptionCode = status.exceptionCode();
_aidl_return->exceptionMessage = status.exceptionMessage();
return ok();
@@ -1839,7 +1851,8 @@
}
if (!createAppDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
- appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr)
+ appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr,
+ nullptr)
.isOk()) {
res = error("Failed to create package target");
goto fail;
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 0f28234..1ec092d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -68,7 +68,8 @@
binder::Status createAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags,
int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return);
+ int32_t targetSdkVersion, int64_t* ceDataInode,
+ int64_t* deDataInode);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
@@ -238,7 +239,7 @@
const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId,
const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
+ int64_t* ceDataInode, int64_t* deDataInode);
binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, const std::string& seInfo);
diff --git a/cmds/installd/binder/android/os/CreateAppDataResult.aidl b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
index 3b8fa6b..463489e 100644
--- a/cmds/installd/binder/android/os/CreateAppDataResult.aidl
+++ b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
@@ -19,6 +19,7 @@
/** {@hide} */
parcelable CreateAppDataResult {
long ceDataInode;
+ long deDataInode;
int exceptionCode;
@utf8InCpp String exceptionMessage;
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index c4071c6..ee91d80 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -197,6 +197,7 @@
std::string app_oat_dir_;
int64_t ce_data_inode_;
+ int64_t de_data_inode_;
std::string secondary_dex_ce_;
std::string secondary_dex_ce_link_;
@@ -261,16 +262,10 @@
}
// Create the app user data.
- binder::Status status = service_->createAppData(
- volume_uuid_,
- package_name_,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode_);
+ binder::Status status =
+ service_->createAppData(volume_uuid_, package_name_, kTestUserId, kAppDataFlags,
+ kTestAppUid, 0 /* previousAppId */, se_info_, kOSdkVersion,
+ &ce_data_inode_, &de_data_inode_);
if (!status.isOk()) {
return ::testing::AssertionFailure() << "Could not create app data: "
<< status.toString8().c_str();
@@ -1350,16 +1345,10 @@
ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
// Run createAppData again which will offer to fix-up the profile directories.
- ASSERT_BINDER_SUCCESS(service_->createAppData(
- volume_uuid_,
- package_name_,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode_));
+ ASSERT_BINDER_SUCCESS(service_->createAppData(volume_uuid_, package_name_, kTestUserId,
+ kAppDataFlags, kTestAppUid, 0 /* previousAppId */,
+ se_info_, kOSdkVersion, &ce_data_inode_,
+ &de_data_inode_));
// Check the file access.
CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
@@ -1492,18 +1481,13 @@
void createAppProfilesForBootMerge(size_t number_of_profiles) {
for (size_t i = 0; i < number_of_profiles; i++) {
int64_t ce_data_inode;
+ int64_t de_data_inode;
std::string package_name = "dummy_test_pkg" + std::to_string(i);
LOG(INFO) << package_name;
- ASSERT_BINDER_SUCCESS(service_->createAppData(
- volume_uuid_,
- package_name,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode));
+ ASSERT_BINDER_SUCCESS(
+ service_->createAppData(volume_uuid_, package_name, kTestUserId, kAppDataFlags,
+ kTestAppUid, 0 /* previousAppId */, se_info_,
+ kOSdkVersion, &ce_data_inode, &de_data_inode));
extra_apps_.push_back(package_name);
extra_ce_data_inodes_.push_back(ce_data_inode);
std::string profile = create_current_profile_path(
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
index 1bbd674..896b78f 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
@@ -35,10 +35,26 @@
/// This API automatically fuzzes provided service
pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) {
- let ptr = binder.as_native_mut() as *mut c_void;
+ let mut binders = [binder];
+ fuzz_multiple_services(&mut binders, fuzzer_data);
+}
+
+/// This API automatically fuzzes provided services
+pub fn fuzz_multiple_services(binders: &mut [&mut SpIBinder], fuzzer_data: &[u8]) {
+ let mut cppBinders = vec![];
+ for binder in binders.iter_mut() {
+ let ptr = binder.as_native_mut() as *mut c_void;
+ cppBinders.push(ptr);
+ }
+
unsafe {
- // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always
+ // Safety: `Vec::as_mut_ptr` and `slice::as_ptr` always
// return valid pointers.
- fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+ fuzzRustService(
+ cppBinders.as_mut_ptr(),
+ cppBinders.len(),
+ fuzzer_data.as_ptr(),
+ fuzzer_data.len(),
+ );
}
}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
index 831bd56..cfdd2ab 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
@@ -21,5 +21,5 @@
void createRandomParcel(void* aParcel, const uint8_t* data, size_t len);
// This API is used by fuzzers to automatically fuzz aidl services
- void fuzzRustService(void* binder, const uint8_t* data, size_t len);
-}
\ No newline at end of file
+ void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len);
+}
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 93ac116..38e6f32 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -61,11 +61,11 @@
while (provider.remaining_bytes() > 0) {
// Most of the AIDL services will have small set of transaction codes.
// TODO(b/295942369) : Add remaining transact codes from IBinder.h
- uint32_t code = provider.ConsumeBool()
- ? provider.ConsumeIntegral<uint32_t>()
- : provider.PickValueInArray<int64_t>(
- {provider.ConsumeIntegralInRange<uint32_t>(0, 100),
- IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION,
+ uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>()
+ : provider.ConsumeBool()
+ ? provider.ConsumeIntegralInRange<uint32_t>(0, 100)
+ : provider.PickValueInArray<uint32_t>(
+ {IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION,
IBinder::SHELL_COMMAND_TRANSACTION, IBinder::INTERFACE_TRANSACTION,
IBinder::SYSPROPS_TRANSACTION, IBinder::EXTENSION_TRANSACTION,
IBinder::TWEET_TRANSACTION, IBinder::LIKE_TRANSACTION});
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index 0b0ca34..84b9ff6 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -22,6 +22,9 @@
// and APEX users, but we need access to it to fuzz.
#include "../../ndk/ibinder_internal.h"
+using android::IBinder;
+using android::sp;
+
namespace android {
void fuzzService(const std::vector<ndk::SpAIBinder>& binders, FuzzedDataProvider&& provider) {
@@ -41,9 +44,14 @@
extern "C" {
// This API is used by fuzzers to automatically fuzz aidl services
-void fuzzRustService(void* binder, const uint8_t* data, size_t len) {
- AIBinder* aiBinder = static_cast<AIBinder*>(binder);
+void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len) {
+ std::vector<sp<IBinder>> cppBinders;
+ for (size_t binderIndex = 0; binderIndex < numBinders; ++binderIndex) {
+ AIBinder* aiBinder = static_cast<AIBinder*>(binders[binderIndex]);
+ cppBinders.push_back(aiBinder->getBinder());
+ }
+
FuzzedDataProvider provider(data, len);
- android::fuzzService(aiBinder, std::move(provider));
+ android::fuzzService(cppBinders, std::move(provider));
}
} // extern "C"
diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
index 943fb9f..33a653e 100644
--- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
@@ -54,7 +54,7 @@
if (transaction.has_value()) {
std::FILE* intermediateFile = std::tmpfile();
- android::base::unique_fd fdForWriting(fileno(intermediateFile));
+ android::base::unique_fd fdForWriting(dup(fileno(intermediateFile)));
auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting);
std::fclose(intermediateFile);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 1f18b94..82ee95c 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -22,6 +22,7 @@
#include <GrBackendSemaphore.h>
#include <GrContextOptions.h>
+#include <GrTypes.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkColor.h>
@@ -289,12 +290,12 @@
}
if (mGrContext) {
- mGrContext->flushAndSubmit(true);
+ mGrContext->flushAndSubmit(GrSyncCpu::kYes);
mGrContext->abandonContext();
}
if (mProtectedGrContext) {
- mProtectedGrContext->flushAndSubmit(true);
+ mProtectedGrContext->flushAndSubmit(GrSyncCpu::kYes);
mProtectedGrContext->abandonContext();
}
}
@@ -307,7 +308,7 @@
// release any scratch resources before switching into a new mode
if (getActiveGrContext()) {
- getActiveGrContext()->purgeUnlockedResources(true);
+ getActiveGrContext()->purgeUnlockedResources(GrPurgeResourceOptions::kScratchResourcesOnly);
}
// Backend-specific way to switch to protected context
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp
index 7c99a1c..56a3fb4 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.cpp
+++ b/services/inputflinger/InputDeviceMetricsCollector.cpp
@@ -41,7 +41,13 @@
constexpr size_t INTERACTIONS_QUEUE_CAPACITY = 500;
-int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
+int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus, bool isUsiStylus) {
+ if (isUsiStylus) {
+ // This is a stylus connected over the Universal Stylus Initiative (USI) protocol.
+ // For metrics purposes, we treat this protocol as a separate bus.
+ return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USI;
+ }
+
// When adding cases to this switch, also add them to the copy of this method in
// TouchpadInputMapper.cpp.
// TODO(b/286394420): deduplicate this method with the one in TouchpadInputMapper.cpp.
@@ -58,11 +64,12 @@
class : public InputDeviceMetricsLogger {
nanoseconds getCurrentTime() override { return nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); }
- void logInputDeviceUsageReported(const InputDeviceIdentifier& identifier,
+ void logInputDeviceUsageReported(const InputDeviceInfo& info,
const DeviceUsageReport& report) override {
const int32_t durationMillis =
std::chrono::duration_cast<std::chrono::milliseconds>(report.usageDuration).count();
const static std::vector<int32_t> empty;
+ const auto& identifier = info.getIdentifier();
ALOGD_IF(DEBUG, "Usage session reported for device: %s", identifier.name.c_str());
ALOGD_IF(DEBUG, " Total duration: %dms", durationMillis);
@@ -90,7 +97,9 @@
durMillis);
}
util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
- identifier.version, linuxBusToInputDeviceBusEnum(identifier.bus),
+ identifier.version,
+ linuxBusToInputDeviceBusEnum(identifier.bus,
+ info.getUsiVersion().has_value()),
durationMillis, sources, durationsPerSource, uids, durationsPerUid);
}
} sStatsdLogger;
@@ -295,21 +304,21 @@
if (newDeviceInfos.count(deviceId) != 0) {
continue;
}
- onInputDeviceRemoved(deviceId, info.getIdentifier());
+ onInputDeviceRemoved(deviceId, info);
}
std::swap(newDeviceInfos, mLoggedDeviceInfos);
}
void InputDeviceMetricsCollector::onInputDeviceRemoved(DeviceId deviceId,
- const InputDeviceIdentifier& identifier) {
+ const InputDeviceInfo& info) {
auto it = mActiveUsageSessions.find(deviceId);
if (it == mActiveUsageSessions.end()) {
return;
}
// Report usage for that device if there is an active session.
auto& [_, activeSession] = *it;
- mLogger.logInputDeviceUsageReported(identifier, activeSession.finishSession());
+ mLogger.logInputDeviceUsageReported(info, activeSession.finishSession());
mActiveUsageSessions.erase(it);
// We don't remove this from mLoggedDeviceInfos because it will be updated in
@@ -365,8 +374,7 @@
auto activeSessionIt = mActiveUsageSessions.find(deviceId);
LOG_ALWAYS_FATAL_IF(activeSessionIt == mActiveUsageSessions.end());
auto& [_, activeSession] = *activeSessionIt;
- mLogger.logInputDeviceUsageReported(infoIt->second.getIdentifier(),
- activeSession.finishSession());
+ mLogger.logInputDeviceUsageReported(infoIt->second, activeSession.finishSession());
mActiveUsageSessions.erase(activeSessionIt);
}
}
diff --git a/services/inputflinger/InputDeviceMetricsCollector.h b/services/inputflinger/InputDeviceMetricsCollector.h
index c70e6d4..1f7c5d9 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.h
+++ b/services/inputflinger/InputDeviceMetricsCollector.h
@@ -110,8 +110,7 @@
UidUsageBreakdown uidBreakdown;
};
- virtual void logInputDeviceUsageReported(const InputDeviceIdentifier&,
- const DeviceUsageReport&) = 0;
+ virtual void logInputDeviceUsageReported(const InputDeviceInfo&, const DeviceUsageReport&) = 0;
virtual ~InputDeviceMetricsLogger() = default;
};
@@ -189,7 +188,7 @@
std::map<DeviceId, ActiveSession> mActiveUsageSessions;
void onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos);
- void onInputDeviceRemoved(DeviceId deviceId, const InputDeviceIdentifier& identifier);
+ void onInputDeviceRemoved(DeviceId deviceId, const InputDeviceInfo& info);
using SourceProvider = std::function<std::set<InputDeviceUsageSource>(const InputDeviceInfo&)>;
void onInputDeviceUsage(DeviceId deviceId, std::chrono::nanoseconds eventTime,
const SourceProvider& getSources);
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 3e5e01e..c76fec7 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -129,7 +129,13 @@
mapper->consumeGesture(gesture);
}
-int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
+int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus, bool isUsiStylus) {
+ if (isUsiStylus) {
+ // This is a stylus connected over the Universal Stylus Initiative (USI) protocol.
+ // For metrics purposes, we treat this protocol as a separate bus.
+ return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USI;
+ }
+
// When adding cases to this switch, also add them to the copy of this method in
// InputDeviceMetricsCollector.cpp.
// TODO(b/286394420): deduplicate this method with the one in InputDeviceMetricsCollector.cpp.
@@ -203,8 +209,8 @@
for (auto& [id, counters] : mCounters) {
auto [busId, vendorId, productId, versionId] = id;
addAStatsEvent(outEventList, android::util::TOUCHPAD_USAGE, vendorId, productId,
- versionId, linuxBusToInputDeviceBusEnum(busId), counters.fingers,
- counters.palms, counters.twoFingerSwipeGestures,
+ versionId, linuxBusToInputDeviceBusEnum(busId, /*isUsi=*/false),
+ counters.fingers, counters.palms, counters.twoFingerSwipeGestures,
counters.threeFingerSwipeGestures, counters.fourFingerSwipeGestures,
counters.pinchGestures);
}
diff --git a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
index 2ff64c8..7ccfaca 100644
--- a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
+++ b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
@@ -53,7 +53,7 @@
constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-InputDeviceIdentifier getIdentifier(int32_t id = DEVICE_ID) {
+InputDeviceIdentifier generateTestIdentifier(int32_t id = DEVICE_ID) {
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME + "_" + std::to_string(id);
identifier.location = LOCATION;
@@ -69,8 +69,8 @@
uint32_t sources = TOUCHSCREEN | STYLUS,
bool isAlphabetic = false) {
auto info = InputDeviceInfo();
- info.initialize(id, /*generation=*/1, /*controllerNumber=*/1, getIdentifier(id), "alias",
- /*isExternal=*/false, /*hasMic=*/false, ADISPLAY_ID_NONE);
+ info.initialize(id, /*generation=*/1, /*controllerNumber=*/1, generateTestIdentifier(id),
+ "alias", /*isExternal=*/false, /*hasMic=*/false, ADISPLAY_ID_NONE);
info.addSource(sources);
info.setKeyboardType(isAlphabetic ? AINPUT_KEYBOARD_TYPE_ALPHABETIC
: AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
@@ -81,6 +81,8 @@
generateTestDeviceInfo(DEVICE_ID, KEY_SOURCES, /*isAlphabetic=*/true);
const InputDeviceInfo NON_ALPHABETIC_KEYBOARD_INFO =
generateTestDeviceInfo(DEVICE_ID, KEY_SOURCES, /*isAlphabetic=*/false);
+const InputDeviceInfo TOUCHSCREEN_STYLUS_INFO = generateTestDeviceInfo(DEVICE_ID);
+const InputDeviceInfo SECOND_TOUCHSCREEN_STYLUS_INFO = generateTestDeviceInfo(DEVICE_ID_2);
std::set<gui::Uid> uids(std::initializer_list<int32_t> vals) {
std::set<gui::Uid> set;
@@ -351,12 +353,12 @@
TestInputListener mTestListener;
InputDeviceMetricsCollector mMetricsCollector{mTestListener, *this, USAGE_TIMEOUT};
- void assertUsageLogged(InputDeviceIdentifier identifier, nanoseconds duration,
+ void assertUsageLogged(const InputDeviceInfo& info, nanoseconds duration,
std::optional<SourceUsageBreakdown> sourceBreakdown = {},
std::optional<UidUsageBreakdown> uidBreakdown = {}) {
ASSERT_GE(mLoggedUsageSessions.size(), 1u);
- const auto& [loggedIdentifier, report] = *mLoggedUsageSessions.begin();
- ASSERT_EQ(identifier, loggedIdentifier);
+ const auto& [loggedInfo, report] = *mLoggedUsageSessions.begin();
+ ASSERT_EQ(info.getIdentifier(), loggedInfo.getIdentifier());
ASSERT_EQ(duration, report.usageDuration);
if (sourceBreakdown) {
ASSERT_EQ(sourceBreakdown, report.sourceBreakdown);
@@ -387,14 +389,14 @@
}
private:
- std::vector<std::tuple<InputDeviceIdentifier, DeviceUsageReport>> mLoggedUsageSessions;
+ std::vector<std::tuple<InputDeviceInfo, DeviceUsageReport>> mLoggedUsageSessions;
nanoseconds mCurrentTime{TIME};
nanoseconds getCurrentTime() override { return mCurrentTime; }
- void logInputDeviceUsageReported(const InputDeviceIdentifier& identifier,
+ void logInputDeviceUsageReported(const InputDeviceInfo& info,
const DeviceUsageReport& report) override {
- mLoggedUsageSessions.emplace_back(identifier, report);
+ mLoggedUsageSessions.emplace_back(info, report);
}
};
@@ -438,7 +440,7 @@
}
TEST_F(InputDeviceMetricsCollectorTest, LogsSingleEventUsageSession) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
// Device was used.
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
@@ -448,11 +450,11 @@
setCurrentTime(TIME + USAGE_TIMEOUT);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
// The usage session has zero duration because it consisted of only one event.
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 0ns));
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 0ns));
}
TEST_F(InputDeviceMetricsCollectorTest, LogsMultipleEventUsageSession) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
// Device was used.
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
@@ -468,11 +470,11 @@
// Device was used again after the usage timeout.
setCurrentTime(TIME + 42ns + 2 * USAGE_TIMEOUT);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 42ns));
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 42ns));
}
TEST_F(InputDeviceMetricsCollectorTest, RemovingDeviceEndsUsageSession) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
// Device was used.
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
@@ -485,12 +487,12 @@
// The device was removed before the usage timeout expired.
setCurrentTime(TIME + 42ns);
mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {}});
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 21ns));
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 21ns));
}
TEST_F(InputDeviceMetricsCollectorTest, TracksUsageFromDifferentDevicesIndependently) {
mMetricsCollector.notifyInputDevicesChanged(
- {/*id=*/0, {generateTestDeviceInfo(), generateTestDeviceInfo(DEVICE_ID_2)}});
+ {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
// Device 1 was used.
setCurrentTime(TIME);
@@ -509,7 +511,7 @@
// Device 1 was used after its usage timeout expired. Its usage session is reported.
setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(DEVICE_ID), 100ns));
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns));
// Device 2 was used.
setCurrentTime(TIME + 350ns + USAGE_TIMEOUT);
@@ -525,13 +527,14 @@
setCurrentTime(TIME + 400ns + (2 * USAGE_TIMEOUT));
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
// Since Device 2's usage session ended, its usage should be reported.
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(DEVICE_ID_2), 150ns + USAGE_TIMEOUT));
+ ASSERT_NO_FATAL_FAILURE(
+ assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 150ns + USAGE_TIMEOUT));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
}
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown;
// Use touchscreen.
@@ -576,7 +579,7 @@
100ns + USAGE_TIMEOUT);
// Verify that only one usage session was logged for the device, and that session was broken
// down by source correctly.
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(),
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO,
400ns + USAGE_TIMEOUT + USAGE_TIMEOUT,
expectedSourceBreakdown));
@@ -585,7 +588,7 @@
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource_TrackSourceByDevice) {
mMetricsCollector.notifyInputDevicesChanged(
- {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID), generateTestDeviceInfo(DEVICE_ID_2)}});
+ {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown1;
InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown2;
@@ -602,15 +605,15 @@
expectedSourceBreakdown1.emplace_back(InputDeviceUsageSource::TOUCHSCREEN, 100ns);
expectedSourceBreakdown2.emplace_back(InputDeviceUsageSource::STYLUS_DIRECT, 100ns);
ASSERT_NO_FATAL_FAILURE(
- assertUsageLogged(getIdentifier(DEVICE_ID), 100ns, expectedSourceBreakdown1));
+ assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns, expectedSourceBreakdown1));
ASSERT_NO_FATAL_FAILURE(
- assertUsageLogged(getIdentifier(DEVICE_ID_2), 100ns, expectedSourceBreakdown2));
+ assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 100ns, expectedSourceBreakdown2));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
}
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource_MultiSourceEvent) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo(DEVICE_ID)}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
@@ -634,13 +637,13 @@
expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::STYLUS_DIRECT, 200ns);
expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::TOUCHSCREEN, 300ns);
ASSERT_NO_FATAL_FAILURE(
- assertUsageLogged(getIdentifier(DEVICE_ID), 400ns, expectedSourceBreakdown));
+ assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 400ns, expectedSourceBreakdown));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
}
TEST_F(InputDeviceMetricsCollectorTest, UidsNotTrackedWhenThereIsNoActiveSession) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
// Notify interaction with UIDs before the device is used.
mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
@@ -665,14 +668,15 @@
// The first usage session is logged.
static const UidUsageBreakdown emptyBreakdown;
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 100ns, /*sourceBreakdown=*/{},
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns,
+ /*sourceBreakdown=*/{},
/*uidBreakdown=*/emptyBreakdown));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
}
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
UidUsageBreakdown expectedUidBreakdown;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
@@ -691,14 +695,14 @@
// Remove the device to force the usage session to be logged.
mMetricsCollector.notifyInputDevicesChanged({});
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 200ns, /*sourceBreakdown=*/{},
- expectedUidBreakdown));
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 200ns,
+ /*sourceBreakdown=*/{}, expectedUidBreakdown));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
}
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid_TracksMultipleSessionsForUid) {
- mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
+ mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
UidUsageBreakdown expectedUidBreakdown;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
@@ -742,7 +746,7 @@
expectedUidBreakdown.emplace_back(2, 0ns);
expectedUidBreakdown.emplace_back(3, 100ns);
expectedUidBreakdown.emplace_back(4, 100ns);
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(), 500ns + USAGE_TIMEOUT,
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 500ns + USAGE_TIMEOUT,
/*sourceBreakdown=*/{}, expectedUidBreakdown));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
@@ -750,7 +754,7 @@
TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid_TracksUidsByDevice) {
mMetricsCollector.notifyInputDevicesChanged(
- {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID), generateTestDeviceInfo(DEVICE_ID_2)}});
+ {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
UidUsageBreakdown expectedUidBreakdown1;
UidUsageBreakdown expectedUidBreakdown2;
@@ -773,9 +777,9 @@
expectedUidBreakdown2.emplace_back(1, 100ns);
expectedUidBreakdown2.emplace_back(3, 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(DEVICE_ID), 200ns,
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 200ns,
/*sourceBreakdown=*/{}, expectedUidBreakdown1));
- ASSERT_NO_FATAL_FAILURE(assertUsageLogged(getIdentifier(DEVICE_ID_2), 100ns,
+ ASSERT_NO_FATAL_FAILURE(assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 100ns,
/*sourceBreakdown=*/{}, expectedUidBreakdown2));
ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 70ccaf8..252ba8e 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -208,12 +208,12 @@
return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
}
-void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps displayFps, Fps renderFps) {
- ATRACE_INT(mActiveModeFPSTrace.c_str(), displayFps.getIntValue());
+void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) {
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), vsyncRate.getIntValue());
ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue());
mRefreshRateSelector->setActiveMode(modeId, renderFps);
- updateRefreshRateOverlayRate(displayFps, renderFps);
+ updateRefreshRateOverlayRate(vsyncRate, renderFps);
}
status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
@@ -230,14 +230,14 @@
mIsModeSetPending = true;
const auto& pendingMode = *info.modeOpt->modePtr;
- ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), pendingMode.getFps().getIntValue());
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), pendingMode.getVsyncRate().getIntValue());
return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), pendingMode.getHwcId(),
constraints, outTimeline);
}
-void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps displayFps, Fps renderFps) {
- setActiveMode(modeId, displayFps, renderFps);
+void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) {
+ setActiveMode(modeId, vsyncRate, renderFps);
mIsModeSetPending = false;
}
@@ -253,7 +253,7 @@
return vsyncPeriod;
}
- return refreshRateSelector().getActiveMode().modePtr->getVsyncPeriod();
+ return refreshRateSelector().getActiveMode().modePtr->getVsyncRate().getPeriodNsecs();
}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
@@ -466,17 +466,19 @@
features |= RefreshRateOverlay::Features::SetByHwc;
}
+ // TODO(b/296636258) Update to use the render rate range in VRR mode.
const auto fpsRange = mRefreshRateSelector->getSupportedRefreshRateRange();
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, features);
mRefreshRateOverlay->setLayerStack(getLayerStack());
mRefreshRateOverlay->setViewport(getSize());
- updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps, setByHwc);
+ updateRefreshRateOverlayRate(getActiveMode().modePtr->getVsyncRate(), getActiveMode().fps,
+ setByHwc);
}
-void DisplayDevice::updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc) {
+void DisplayDevice::updateRefreshRateOverlayRate(Fps vsyncRate, Fps renderFps, bool setByHwc) {
ATRACE_CALL();
if (mRefreshRateOverlay && (!mRefreshRateOverlay->isSetByHwc() || setByHwc)) {
- mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps);
+ mRefreshRateOverlay->changeRefreshRate(vsyncRate, renderFps);
}
}
@@ -486,7 +488,7 @@
const auto newMode =
mRefreshRateSelector->onKernelTimerChanged(desiredModeId, timerExpired);
if (newMode) {
- updateRefreshRateOverlayRate(newMode->modePtr->getFps(), newMode->fps);
+ updateRefreshRateOverlayRate(newMode->modePtr->getVsyncRate(), newMode->fps);
return true;
}
}
@@ -541,14 +543,14 @@
return DesiredActiveModeAction::None;
}
- setActiveMode(desiredMode.getId(), desiredMode.getFps(), info.modeOpt->fps);
+ setActiveMode(desiredMode.getId(), desiredMode.getVsyncRate(), info.modeOpt->fps);
return DesiredActiveModeAction::InitiateRenderRateSwitch;
}
// Set the render frame rate to the current physical refresh rate to schedule the next
// frame as soon as possible.
- setActiveMode(currentMode.modePtr->getId(), currentMode.modePtr->getFps(),
- currentMode.modePtr->getFps());
+ setActiveMode(currentMode.modePtr->getId(), currentMode.modePtr->getVsyncRate(),
+ currentMode.modePtr->getVsyncRate());
// Initiate a mode change.
mDesiredActiveModeChanged = true;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index a3fa701..a044534 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -224,14 +224,14 @@
return mRefreshRateSelector->getActiveMode();
}
- void setActiveMode(DisplayModeId, Fps displayFps, Fps renderFps);
+ void setActiveMode(DisplayModeId, Fps vsyncRate, Fps renderFps);
status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline)
REQUIRES(kMainThreadContext);
- void finalizeModeChange(DisplayModeId, Fps displayFps, Fps renderFps)
+ void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps)
REQUIRES(kMainThreadContext);
scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; }
@@ -246,7 +246,7 @@
// Enables an overlay to be displayed with the current refresh rate
void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate,
bool showInMiddle) REQUIRES(kMainThreadContext);
- void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false);
+ void updateRefreshRateOverlayRate(Fps vsyncRate, Fps renderFps, bool setByHwc = false);
bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 1810925..422513b 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -32,6 +32,8 @@
#include "DisplayHardware/Hal.h"
#include "Scheduler/StrongTyping.h"
+#include <com_android_graphics_surfaceflinger_flags.h>
+
namespace android {
namespace hal = android::hardware::graphics::composer::hal;
@@ -49,6 +51,7 @@
using DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>;
using DisplayModeIterator = DisplayModes::const_iterator;
+using namespace com::android::graphics::surfaceflinger;
class DisplayMode {
public:
@@ -76,7 +79,12 @@
}
Builder& setVsyncPeriod(nsecs_t vsyncPeriod) {
- mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod);
+ mDisplayMode->mVsyncRate = Fps::fromPeriodNsecs(vsyncPeriod);
+ return *this;
+ }
+
+ Builder& setVrrConfig(std::optional<hal::VrrConfig> vrrConfig) {
+ mDisplayMode->mVrrConfig = std::move(vrrConfig);
return *this;
}
@@ -130,8 +138,17 @@
int32_t getWidth() const { return mResolution.getWidth(); }
int32_t getHeight() const { return mResolution.getHeight(); }
- Fps getFps() const { return mFps; }
- nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
+ // Peak refresh rate represents the highest refresh rate that can be used
+ // for the presentation.
+ Fps getPeakFps() const {
+ return flags::vrr_config() && mVrrConfig
+ ? Fps::fromPeriodNsecs(mVrrConfig->minFrameIntervalNs)
+ : mVsyncRate;
+ }
+
+ Fps getVsyncRate() const { return mVsyncRate; }
+
+ std::optional<hal::VrrConfig> getVrrConfig() const { return mVrrConfig; }
struct Dpi {
float x = -1;
@@ -155,23 +172,25 @@
PhysicalDisplayId mPhysicalDisplayId;
ui::Size mResolution;
- Fps mFps;
+ Fps mVsyncRate;
Dpi mDpi;
int32_t mGroup = -1;
+ std::optional<hal::VrrConfig> mVrrConfig;
};
inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) {
return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() &&
- lhs.getVsyncPeriod() == rhs.getVsyncPeriod() && lhs.getDpi() == rhs.getDpi() &&
- lhs.getGroup() == rhs.getGroup();
+ lhs.getVsyncRate().getPeriodNsecs() == rhs.getVsyncRate().getPeriodNsecs() &&
+ lhs.getDpi() == rhs.getDpi() && lhs.getGroup() == rhs.getGroup();
}
inline std::string to_string(const DisplayMode& mode) {
- return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, refreshRate=%s, "
- "dpi=%.2fx%.2f, group=%d}",
+ return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, vsyncRate=%s, "
+ "dpi=%.2fx%.2f, group=%d, vrrConfig=%s}",
mode.getId().value(), mode.getHwcId(), mode.getWidth(),
- mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpi().x,
- mode.getDpi().y, mode.getGroup());
+ mode.getHeight(), to_string(mode.getVsyncRate()).c_str(),
+ mode.getDpi().x, mode.getDpi().y, mode.getGroup(),
+ to_string(mode.getVrrConfig()).c_str());
}
template <typename... DisplayModePtrs>
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a9bb928..812621f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -285,13 +285,12 @@
std::vector<HWCDisplayMode> modes;
modes.reserve(configs.size());
for (auto config : configs) {
- auto hwcMode = HWCDisplayMode{
- .hwcId = static_cast<hal::HWConfigId>(config.configId),
- .width = config.width,
- .height = config.height,
- .vsyncPeriod = config.vsyncPeriod,
- .configGroup = config.configGroup,
- };
+ auto hwcMode = HWCDisplayMode{.hwcId = static_cast<hal::HWConfigId>(config.configId),
+ .width = config.width,
+ .height = config.height,
+ .vsyncPeriod = config.vsyncPeriod,
+ .configGroup = config.configGroup,
+ .vrrConfig = config.vrrConfig};
if (config.dpi) {
hwcMode.dpiX = config.dpi->x;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 86f3825..b4d3d28 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -102,11 +102,13 @@
float dpiX = -1.f;
float dpiY = -1.f;
int32_t configGroup = -1;
+ std::optional<hal::VrrConfig> vrrConfig;
friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) {
return os << "id=" << mode.hwcId << " res=" << mode.width << "x" << mode.height
<< " vsyncPeriod=" << mode.vsyncPeriod << " dpi=" << mode.dpiX << "x"
- << mode.dpiY << " group=" << mode.configGroup;
+ << mode.dpiY << " group=" << mode.configGroup
+ << " vrrConfig=" << to_string(mode.vrrConfig).c_str();
}
};
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index e95ae89..20f7548 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -24,6 +24,7 @@
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
+#include <aidl/android/hardware/graphics/composer3/VrrConfig.h>
#define ERROR_HAS_CHANGES 5
@@ -73,6 +74,7 @@
using VsyncPeriodChangeConstraints = IComposerClient::VsyncPeriodChangeConstraints;
using Hdr = aidl::android::hardware::graphics::common::Hdr;
using DisplayConfiguration = V3_0::DisplayConfiguration;
+using VrrConfig = V3_0::VrrConfig;
} // namespace hardware::graphics::composer::hal
@@ -148,6 +150,34 @@
}
}
+inline std::string to_string(
+ const std::optional<aidl::android::hardware::graphics::composer3::VrrConfig>& vrrConfig) {
+ if (vrrConfig) {
+ std::ostringstream out;
+ out << "{minFrameIntervalNs=" << vrrConfig->minFrameIntervalNs << ", ";
+ out << "frameIntervalPowerHints={";
+ if (vrrConfig->frameIntervalPowerHints) {
+ const auto& powerHint = *vrrConfig->frameIntervalPowerHints;
+ for (size_t i = 0; i < powerHint.size(); i++) {
+ if (i > 0) out << ", ";
+ out << "[frameIntervalNs=" << powerHint[i]->frameIntervalNs
+ << ", averageRefreshPeriodNs=" << powerHint[i]->averageRefreshPeriodNs << "]";
+ }
+ }
+ out << "}, ";
+ out << "notifyExpectedPresentConfig={";
+ if (vrrConfig->notifyExpectedPresentConfig) {
+ out << "notifyExpectedPresentHeadsUpNs="
+ << vrrConfig->notifyExpectedPresentConfig->notifyExpectedPresentHeadsUpNs
+ << ", notifyExpectedPresentTimeoutNs="
+ << vrrConfig->notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs;
+ }
+ out << "}}";
+ return out.str();
+ }
+ return "N/A";
+}
+
inline std::string to_string(hardware::graphics::composer::hal::V2_4::Error error) {
// 5 is reserved for historical reason, during validation 5 means has changes.
if (ERROR_HAS_CHANGES == static_cast<int32_t>(error)) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2bbfa42..2684000 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3092,6 +3092,32 @@
return true;
}
+void Layer::releasePreviousBuffer() {
+ mReleasePreviousBuffer = true;
+ if (!mBufferInfo.mBuffer ||
+ (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
+ mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) {
+ // If mDrawingState has a buffer, and we are about to update again
+ // before swapping to drawing state, then the first buffer will be
+ // dropped and we should decrement the pending buffer count and
+ // call any release buffer callbacks if set.
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
+ mDrawingState.acquireFence);
+ decrementPendingBufferCount();
+ if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
+ mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
+ addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX, systemTime());
+ mDrawingState.bufferSurfaceFrameTX.reset();
+ }
+ } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
+ mLastClientCompositionFence);
+ mLastClientCompositionFence = nullptr;
+ }
+}
+
void Layer::resetDrawingStateBufferInfo() {
mDrawingState.producerId = 0;
mDrawingState.frameNumber = 0;
@@ -3116,29 +3142,7 @@
ATRACE_FORMAT_INSTANT("setBuffer %s - %" PRIu64, getDebugName(), frameNumber);
if (mDrawingState.buffer) {
- mReleasePreviousBuffer = true;
- if (!mBufferInfo.mBuffer ||
- (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
- mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) {
- // If mDrawingState has a buffer, and we are about to update again
- // before swapping to drawing state, then the first buffer will be
- // dropped and we should decrement the pending buffer count and
- // call any release buffer callbacks if set.
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mDrawingState.acquireFence);
- decrementPendingBufferCount();
- if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
- mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
- addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX, systemTime());
- mDrawingState.bufferSurfaceFrameTX.reset();
- }
- } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mLastClientCompositionFence);
- mLastClientCompositionFence = nullptr;
- }
+ releasePreviousBuffer();
} else if (buffer) {
// if we are latching a buffer for the first time then clear the mLastLatchTime since
// we don't want to incorrectly classify a frame if we miss the desired present time.
@@ -3156,6 +3160,12 @@
mDrawingState.bufferSurfaceFrameTX = nullptr;
setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
return true;
+ } else {
+ // release sideband stream if it exists and a non null buffer is being set
+ if (mDrawingState.sidebandStream != nullptr) {
+ mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
+ mDrawingState.sidebandStream = nullptr;
+ }
}
if ((mDrawingState.producerId > bufferData.producerId) ||
@@ -3344,7 +3354,8 @@
return true;
}
-bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
+bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream, const FrameTimelineInfo& info,
+ nsecs_t postTime) {
if (mDrawingState.sidebandStream == sidebandStream) return false;
if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) {
@@ -3355,6 +3366,12 @@
mDrawingState.sidebandStream = sidebandStream;
mDrawingState.modified = true;
+ if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) {
+ releasePreviousBuffer();
+ resetDrawingStateBufferInfo();
+ mDrawingState.bufferSurfaceFrameTX = nullptr;
+ setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
+ }
setTransactionFlags(eTransactionNeeded);
if (!mSidebandStreamChanged.exchange(true)) {
// mSidebandStreamChanged was false
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index dc4ceb0..0b0cef5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -317,7 +317,8 @@
bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
bool setApi(int32_t /*api*/);
- bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/);
+ bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/,
+ const FrameTimelineInfo& /* info*/, nsecs_t /* postTime */);
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/,
bool willPresent);
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace)
@@ -1204,6 +1205,7 @@
half4 mBorderColor;
void setTransformHintLegacy(ui::Transform::RotationFlags);
+ void releasePreviousBuffer();
void resetDrawingStateBufferInfo();
// Transform hint provided to the producer. This must be accessed holding
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 577211f..e918dc9 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -27,7 +27,7 @@
namespace android {
-auto RefreshRateOverlay::draw(int displayFps, int renderFps, SkColor color,
+auto RefreshRateOverlay::draw(int vsyncRate, int renderFps, SkColor color,
ui::Transform::RotationFlags rotation, ftl::Flags<Features> features)
-> Buffers {
const size_t loopCount = features.test(Features::Spinner) ? 6 : 1;
@@ -70,7 +70,7 @@
canvas->setMatrix(canvasTransform);
int left = 0;
- drawNumber(displayFps, left, color, *canvas);
+ drawNumber(vsyncRate, left, color, *canvas);
left += 3 * (kDigitWidth + kDigitSpace);
if (features.test(Features::Spinner)) {
switch (i) {
@@ -153,7 +153,7 @@
.apply();
}
-auto RefreshRateOverlay::getOrCreateBuffers(Fps displayFps, Fps renderFps) -> const Buffers& {
+auto RefreshRateOverlay::getOrCreateBuffers(Fps vsyncRate, Fps renderFps) -> const Buffers& {
static const Buffers kNoBuffers;
if (!mSurfaceControl) return kNoBuffers;
@@ -180,16 +180,16 @@
createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
BufferCache::const_iterator it =
- mBufferCache.find({displayFps.getIntValue(), renderFps.getIntValue(), transformHint});
+ mBufferCache.find({vsyncRate.getIntValue(), renderFps.getIntValue(), transformHint});
if (it == mBufferCache.end()) {
// HWC minFps is not known by the framework in order
// to consider lower rates we set minFps to 0.
const int minFps = isSetByHwc() ? 0 : mFpsRange.min.getIntValue();
const int maxFps = mFpsRange.max.getIntValue();
- // Clamp to the range. The current displayFps may be outside of this range if the display
+ // Clamp to the range. The current vsyncRate may be outside of this range if the display
// has changed its set of supported refresh rates.
- const int displayIntFps = std::clamp(displayFps.getIntValue(), minFps, maxFps);
+ const int displayIntFps = std::clamp(vsyncRate.getIntValue(), minFps, maxFps);
const int renderIntFps = renderFps.getIntValue();
// Ensure non-zero range to avoid division by zero.
@@ -242,17 +242,17 @@
createTransaction().setLayerStack(mSurfaceControl->get(), stack).apply();
}
-void RefreshRateOverlay::changeRefreshRate(Fps displayFps, Fps renderFps) {
- mDisplayFps = displayFps;
+void RefreshRateOverlay::changeRefreshRate(Fps vsyncRate, Fps renderFps) {
+ mVsyncRate = vsyncRate;
mRenderFps = renderFps;
- const auto buffer = getOrCreateBuffers(displayFps, renderFps)[mFrame];
+ const auto buffer = getOrCreateBuffers(vsyncRate, renderFps)[mFrame];
createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
}
void RefreshRateOverlay::animate() {
- if (!mFeatures.test(Features::Spinner) || !mDisplayFps) return;
+ if (!mFeatures.test(Features::Spinner) || !mVsyncRate) return;
- const auto& buffers = getOrCreateBuffers(*mDisplayFps, *mRenderFps);
+ const auto& buffers = getOrCreateBuffers(*mVsyncRate, *mRenderFps);
mFrame = (mFrame + 1) % buffers.size();
const auto buffer = buffers[mFrame];
createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 65c61cb..c0fc79b 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -56,7 +56,7 @@
private:
using Buffers = std::vector<sp<GraphicBuffer>>;
- static Buffers draw(int displayFps, int renderFps, SkColor, ui::Transform::RotationFlags,
+ static Buffers draw(int vsyncRate, int renderFps, SkColor, ui::Transform::RotationFlags,
ftl::Flags<Features>);
static void drawNumber(int number, int left, SkColor, SkCanvas&);
@@ -65,12 +65,12 @@
SurfaceComposerClient::Transaction createTransaction() const;
struct Key {
- int displayFps;
+ int vsyncRate;
int renderFps;
ui::Transform::RotationFlags flags;
bool operator==(Key other) const {
- return displayFps == other.displayFps && renderFps == other.renderFps &&
+ return vsyncRate == other.vsyncRate && renderFps == other.renderFps &&
flags == other.flags;
}
};
@@ -78,7 +78,7 @@
using BufferCache = ftl::SmallMap<Key, Buffers, 9>;
BufferCache mBufferCache;
- std::optional<Fps> mDisplayFps;
+ std::optional<Fps> mVsyncRate;
std::optional<Fps> mRenderFps;
size_t mFrame = 0;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index be28e98..3ee6a4d 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -39,12 +39,16 @@
#include "../SurfaceFlingerProperties.h"
#include "RefreshRateSelector.h"
+#include <com_android_graphics_surfaceflinger_flags.h>
+
#undef LOG_TAG
#define LOG_TAG "RefreshRateSelector"
namespace android::scheduler {
namespace {
+using namespace com::android::graphics::surfaceflinger;
+
struct RefreshRateScore {
FrameRateMode frameRateMode;
float overallScore;
@@ -69,7 +73,7 @@
// Add all supported refresh rates.
for (const auto& [id, mode] : modes) {
- knownFrameRates.push_back(mode->getFps());
+ knownFrameRates.push_back(mode->getPeakFps());
}
// Sort and remove duplicates.
@@ -91,17 +95,17 @@
const auto& mode1 = it1->second;
const auto& mode2 = it2->second;
- if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) {
+ if (mode1->getVsyncRate().getPeriodNsecs() == mode2->getVsyncRate().getPeriodNsecs()) {
return mode1->getGroup() > mode2->getGroup();
}
- return mode1->getVsyncPeriod() > mode2->getVsyncPeriod();
+ return mode1->getVsyncRate().getPeriodNsecs() > mode2->getVsyncRate().getPeriodNsecs();
});
return sortedModes;
}
-std::pair<unsigned, unsigned> divisorRange(Fps fps, FpsRange range,
+std::pair<unsigned, unsigned> divisorRange(Fps vsyncRate, Fps peakFps, FpsRange range,
RefreshRateSelector::Config::FrameRateOverride config) {
if (config != RefreshRateSelector::Config::FrameRateOverride::Enabled) {
return {1, 1};
@@ -109,8 +113,14 @@
using fps_approx_ops::operator/;
// use signed type as `fps / range.max` might be 0
- const auto start = std::max(1, static_cast<int>(fps / range.max) - 1);
- const auto end = fps /
+ auto start = std::max(1, static_cast<int>(peakFps / range.max) - 1);
+ if (flags::vrr_config()) {
+ start = std::max(1,
+ static_cast<int>(vsyncRate /
+ std::min(range.max, peakFps, fps_approx_ops::operator<)) -
+ 1);
+ }
+ const auto end = vsyncRate /
std::max(range.min, RefreshRateSelector::kMinSupportedFrameRate,
fps_approx_ops::operator<);
@@ -123,7 +133,8 @@
for (const auto it2 : sortedModes) {
const auto& mode2 = it2->second;
- if (RefreshRateSelector::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
+ if (RefreshRateSelector::getFrameRateDivisor(mode1->getPeakFps(),
+ mode2->getPeakFps()) >= 2) {
return true;
}
}
@@ -176,10 +187,12 @@
if (!filterModes(*mode)) {
continue;
}
+ const auto vsyncRate = mode->getVsyncRate();
+ const auto peakFps = mode->getPeakFps();
const auto [start, end] =
- divisorRange(mode->getFps(), renderRange, mConfig.enableFrameRateOverride);
+ divisorRange(vsyncRate, peakFps, renderRange, mConfig.enableFrameRateOverride);
for (auto divisor = start; divisor <= end; divisor++) {
- const auto fps = mode->getFps() / divisor;
+ const auto fps = vsyncRate / divisor;
using fps_approx_ops::operator<;
if (divisor > 1 && fps < kMinSupportedFrameRate) {
break;
@@ -199,28 +212,30 @@
const auto [existingIter, emplaceHappened] =
ratesMap.try_emplace(Key{fps, mode->getGroup()}, it);
if (emplaceHappened) {
- ALOGV("%s: including %s (%s)", __func__, to_string(fps).c_str(),
- to_string(mode->getFps()).c_str());
+ ALOGV("%s: including %s (%s(%s))", __func__, to_string(fps).c_str(),
+ to_string(peakFps).c_str(), to_string(vsyncRate).c_str());
} else {
// If the primary physical range is a single rate, prefer to stay in that rate
// even if there is a lower physical refresh rate available. This would cause more
// cases to stay within the primary physical range
- const Fps existingModeFps = existingIter->second->second->getFps();
+ const Fps existingModeFps = existingIter->second->second->getPeakFps();
const bool existingModeIsPrimaryRange = policy.primaryRangeIsSingleRate() &&
policy.primaryRanges.physical.includes(existingModeFps);
const bool newModeIsPrimaryRange = policy.primaryRangeIsSingleRate() &&
- policy.primaryRanges.physical.includes(mode->getFps());
+ policy.primaryRanges.physical.includes(mode->getPeakFps());
if (newModeIsPrimaryRange == existingModeIsPrimaryRange) {
// We might need to update the map as we found a lower refresh rate
- if (isStrictlyLess(mode->getFps(), existingModeFps)) {
+ if (isStrictlyLess(mode->getPeakFps(), existingModeFps)) {
existingIter->second = it;
- ALOGV("%s: changing %s (%s) as we found a lower physical rate", __func__,
- to_string(fps).c_str(), to_string(mode->getFps()).c_str());
+ ALOGV("%s: changing %s (%s(%s)) as we found a lower physical rate",
+ __func__, to_string(fps).c_str(), to_string(peakFps).c_str(),
+ to_string(vsyncRate).c_str());
}
} else if (newModeIsPrimaryRange) {
existingIter->second = it;
- ALOGV("%s: changing %s (%s) to stay in the primary range", __func__,
- to_string(fps).c_str(), to_string(mode->getFps()).c_str());
+ ALOGV("%s: changing %s (%s(%s)) to stay in the primary range", __func__,
+ to_string(fps).c_str(), to_string(peakFps).c_str(),
+ to_string(vsyncRate).c_str());
}
}
}
@@ -237,8 +252,8 @@
const auto lowestRefreshRateIt =
std::min_element(frameRateModes.begin(), frameRateModes.end(),
[](const FrameRateMode& lhs, const FrameRateMode& rhs) {
- return isStrictlyLess(lhs.modePtr->getFps(),
- rhs.modePtr->getFps());
+ return isStrictlyLess(lhs.modePtr->getVsyncRate(),
+ rhs.modePtr->getVsyncRate());
});
frameRateModes.erase(frameRateModes.begin(), lowestRefreshRateIt);
@@ -623,7 +638,7 @@
}
const bool inPrimaryPhysicalRange =
- policy->primaryRanges.physical.includes(modePtr->getFps());
+ policy->primaryRanges.physical.includes(modePtr->getPeakFps());
const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps);
if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) ||
!inPrimaryRenderRange) &&
@@ -664,21 +679,24 @@
Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
if (fixedSourceLayer && layerBelowThreshold) {
const bool modeAboveThreshold =
- modePtr->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ modePtr->getPeakFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
if (modeAboveThreshold) {
- ALOGV("%s gives %s (%s) fixed source (above threshold) score of %.4f",
+ ALOGV("%s gives %s (%s(%s)) fixed source (above threshold) score of %.4f",
formatLayerInfo(layer, weight).c_str(), to_string(fps).c_str(),
- to_string(modePtr->getFps()).c_str(), layerScore);
+ to_string(modePtr->getPeakFps()).c_str(),
+ to_string(modePtr->getVsyncRate()).c_str(), layerScore);
fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
} else {
- ALOGV("%s gives %s (%s) fixed source (below threshold) score of %.4f",
+ ALOGV("%s gives %s (%s(%s)) fixed source (below threshold) score of %.4f",
formatLayerInfo(layer, weight).c_str(), to_string(fps).c_str(),
- to_string(modePtr->getFps()).c_str(), layerScore);
+ to_string(modePtr->getPeakFps()).c_str(),
+ to_string(modePtr->getVsyncRate()).c_str(), layerScore);
fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
}
} else {
- ALOGV("%s gives %s (%s) score of %.4f", formatLayerInfo(layer, weight).c_str(),
- to_string(fps).c_str(), to_string(modePtr->getFps()).c_str(), layerScore);
+ ALOGV("%s gives %s (%s(%s)) score of %.4f", formatLayerInfo(layer, weight).c_str(),
+ to_string(fps).c_str(), to_string(modePtr->getPeakFps()).c_str(),
+ to_string(modePtr->getVsyncRate()).c_str(), layerScore);
overallScore += weightedLayerScore;
}
}
@@ -699,13 +717,14 @@
[](RefreshRateScore max, RefreshRateScore current) {
return current.overallScore > max.overallScore;
});
- ALOGV("%s (%s) is the best refresh rate without fixed source layers. It is %s the "
+ ALOGV("%s (%s(%s)) is the best refresh rate without fixed source layers. It is %s the "
"threshold for "
"refresh rate multiples",
to_string(maxScoreIt->frameRateMode.fps).c_str(),
- to_string(maxScoreIt->frameRateMode.modePtr->getFps()).c_str(),
+ to_string(maxScoreIt->frameRateMode.modePtr->getPeakFps()).c_str(),
+ to_string(maxScoreIt->frameRateMode.modePtr->getVsyncRate()).c_str(),
maxScoreAboveThreshold ? "above" : "below");
- return maxScoreIt->frameRateMode.modePtr->getFps() >=
+ return maxScoreIt->frameRateMode.modePtr->getPeakFps() >=
Fps::fromValue(mConfig.frameRateMultipleThreshold);
}();
@@ -715,8 +734,9 @@
if (maxScoreAboveThreshold) {
overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
}
- ALOGV("%s (%s) adjusted overallScore is %.4f", to_string(frameRateMode.fps).c_str(),
- to_string(frameRateMode.modePtr->getFps()).c_str(), overallScore);
+ ALOGV("%s (%s(%s)) adjusted overallScore is %.4f", to_string(frameRateMode.fps).c_str(),
+ to_string(frameRateMode.modePtr->getPeakFps()).c_str(),
+ to_string(frameRateMode.modePtr->getVsyncRate()).c_str(), overallScore);
}
// Now that we scored all the refresh rates we need to pick the one that got the highest
@@ -842,6 +862,7 @@
const auto* policyPtr = getCurrentPolicyLocked();
// We don't want to run lower than 30fps
+ // TODO(b/297600226): revise this for dVRR
const Fps minFrameRate = std::max(policyPtr->appRequestRanges.render.min, 30_Hz, isApproxLess);
using fps_approx_ops::operator/;
@@ -933,7 +954,7 @@
const auto current = [&]() REQUIRES(mLock) -> FrameRateMode {
if (desiredActiveModeId) {
const auto& modePtr = mDisplayModes.get(*desiredActiveModeId)->get();
- return FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)};
+ return FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)};
}
return getActiveModeLocked();
@@ -944,7 +965,7 @@
return {};
}
- return timerExpired ? FrameRateMode{min->getFps(), ftl::as_non_null(min)} : current;
+ return timerExpired ? FrameRateMode{min->getPeakFps(), ftl::as_non_null(min)} : current;
}
const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const {
@@ -970,12 +991,12 @@
bool maxByAnchorFound = false;
for (auto it = mPrimaryFrameRates.rbegin(); it != mPrimaryFrameRates.rend(); ++it) {
using namespace fps_approx_ops;
- if (it->modePtr->getFps() > (*max)->getFps()) {
+ if (it->modePtr->getPeakFps() > (*max)->getPeakFps()) {
max = &it->modePtr;
}
if (anchorGroup == it->modePtr->getGroup() &&
- it->modePtr->getFps() >= (*maxByAnchor)->getFps()) {
+ it->modePtr->getPeakFps() >= (*maxByAnchor)->getPeakFps()) {
maxByAnchorFound = true;
maxByAnchor = &it->modePtr;
}
@@ -1053,8 +1074,9 @@
return;
}
- ALOGV("%s(%s) %s (%s) scored %.2f", whence, ftl::enum_string(refreshRateOrder).c_str(),
- to_string(frameRateMode.fps).c_str(), to_string(modePtr->getFps()).c_str(), score);
+ ALOGV("%s(%s) %s (%s(%s)) scored %.2f", whence, ftl::enum_string(refreshRateOrder).c_str(),
+ to_string(frameRateMode.fps).c_str(), to_string(modePtr->getPeakFps()).c_str(),
+ to_string(modePtr->getVsyncRate()).c_str(), score);
ranking.emplace_back(ScoredFrameRate{frameRateMode, score});
};
@@ -1134,8 +1156,8 @@
mDisplayModes = std::move(modes);
const auto activeModeOpt = mDisplayModes.get(activeModeId);
LOG_ALWAYS_FATAL_IF(!activeModeOpt);
- mActiveModeOpt =
- FrameRateMode{activeModeOpt->get()->getFps(), ftl::as_non_null(activeModeOpt->get())};
+ mActiveModeOpt = FrameRateMode{activeModeOpt->get()->getPeakFps(),
+ ftl::as_non_null(activeModeOpt->get())};
const auto sortedModes = sortByRefreshRate(mDisplayModes);
mMinRefreshRateModeIt = sortedModes.front();
@@ -1161,7 +1183,7 @@
if (mConfig.enableFrameRateOverride ==
Config::FrameRateOverride::AppOverrideNativeRefreshRates) {
for (const auto& [_, mode] : mDisplayModes) {
- mAppOverrideNativeRefreshRates.try_emplace(mode->getFps(), ftl::unit);
+ mAppOverrideNativeRefreshRates.try_emplace(mode->getPeakFps(), ftl::unit);
}
}
@@ -1171,7 +1193,7 @@
bool RefreshRateSelector::isPolicyValidLocked(const Policy& policy) const {
// defaultMode must be a valid mode, and within the given refresh rate range.
if (const auto mode = mDisplayModes.get(policy.defaultMode)) {
- if (!policy.primaryRanges.physical.includes(mode->get()->getFps())) {
+ if (!policy.primaryRanges.physical.includes(mode->get()->getPeakFps())) {
ALOGE("Default mode is not in the primary range.");
return false;
}
@@ -1284,8 +1306,8 @@
return mode.getResolution() == defaultMode->getResolution() &&
mode.getDpi() == defaultMode->getDpi() &&
(policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) &&
- ranges.physical.includes(mode.getFps()) &&
- (supportsFrameRateOverride() || ranges.render.includes(mode.getFps()));
+ ranges.physical.includes(mode.getPeakFps()) &&
+ (supportsFrameRateOverride() || ranges.render.includes(mode.getPeakFps()));
};
auto frameRateModes = createFrameRateModes(*policy, filterModes, ranges.render);
@@ -1340,13 +1362,13 @@
auto RefreshRateSelector::getIdleTimerAction() const -> KernelIdleTimerAction {
std::lock_guard lock(mLock);
- const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps();
+ const Fps deviceMinFps = mMinRefreshRateModeIt->second->getPeakFps();
const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked();
// Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
// the min allowed refresh rate is higher than the device min, we do not want to enable the
// timer.
- if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) {
+ if (isStrictlyLess(deviceMinFps, minByPolicy->getPeakFps())) {
return KernelIdleTimerAction::TurnOff;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 73e1d38..9bcbc0e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -253,7 +253,8 @@
FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
std::lock_guard lock(mLock);
- return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()};
+ return {mMinRefreshRateModeIt->second->getPeakFps(),
+ mMaxRefreshRateModeIt->second->getPeakFps()};
}
ftl::Optional<FrameRateMode> onKernelTimerChanged(
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 27c96f7..595550b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -494,7 +494,7 @@
if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
if (!refreshRate) {
- refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
+ refreshRate = display.selectorPtr->getActiveMode().modePtr->getVsyncRate();
}
if (refreshRate->isValid()) {
constexpr bool kForce = false;
@@ -542,7 +542,7 @@
to_string(mode.fps).c_str(), to_string(renderFrameRate).c_str(), id.value);
ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
- to_string(mode.modePtr->getFps()).c_str());
+ to_string(mode.modePtr->getVsyncRate()).c_str());
display.schedulePtr->getTracker().setRenderRate(renderFrameRate);
}
@@ -717,7 +717,7 @@
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const Fps refreshRate = pacesetterSelectorPtr()->getActiveMode().modePtr->getFps();
+ const Fps refreshRate = pacesetterSelectorPtr()->getActiveMode().modePtr->getPeakFps();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
using namespace fps_approx_ops;
@@ -877,7 +877,7 @@
newVsyncSchedulePtr = pacesetter.schedulePtr;
- const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getFps();
+ const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getVsyncRate();
constexpr bool kForce = true;
newVsyncSchedulePtr->startPeriodTransition(refreshRate.getPeriod(), kForce);
}
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index a24e43f..b6cb373 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -143,7 +143,7 @@
*/
class WorkDuration : public VsyncConfiguration {
public:
- explicit WorkDuration(Fps currentRefrshRate);
+ explicit WorkDuration(Fps currentRefreshRate);
protected:
// Used for unit tests
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
index db38ebe..59a6df2 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
@@ -36,7 +36,8 @@
};
inline std::string to_string(const FrameRateMode& mode) {
- return to_string(mode.fps) + " (" + to_string(mode.modePtr->getFps()) + ")";
+ return to_string(mode.fps) + " (" + to_string(mode.modePtr->getPeakFps()) + "(" +
+ to_string(mode.modePtr->getVsyncRate()) + "))";
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e6a2de5..1a08244 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -498,6 +498,7 @@
mMiscFlagValue = flags::misc1();
mConnectedDisplayFlagValue = flags::connected_display();
mMisc2FlagEarlyBootValue = flags::late_boot_misc2();
+ mVrrConfigFlagValue = flags::vrr_config();
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -1043,8 +1044,8 @@
outMode.xDpi = xDpi;
outMode.yDpi = yDpi;
- const nsecs_t period = mode->getVsyncPeriod();
- outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
+ const auto peakFps = mode->getPeakFps();
+ outMode.refreshRate = peakFps.getValue();
const auto vsyncConfigSet =
mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate));
@@ -1064,7 +1065,7 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000;
+ outMode.presentationDeadline = peakFps.getPeriodNsecs() - outMode.sfVsyncOffset + 1000000;
excludeDolbyVisionIf4k30Present(display->getHdrCapabilities().getSupportedHdrTypes(),
outMode);
info->supportedDisplayModes.push_back(outMode);
@@ -1199,7 +1200,7 @@
// Start receiving vsync samples now, so that we can detect a period
// switch.
mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */,
- mode.modePtr->getFps());
+ mode.modePtr->getVsyncRate());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
@@ -1253,7 +1254,7 @@
const auto& snapshot = snapshotRef.get();
const auto fpsOpt = snapshot.displayModes().get(modeId).transform(
- [](const DisplayModePtr& mode) { return mode->getFps(); });
+ [](const DisplayModePtr& mode) { return mode->getPeakFps(); });
if (!fpsOpt) {
ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(),
@@ -1302,7 +1303,7 @@
}
const auto& activeMode = *upcomingModeInfo.modeOpt;
- display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getFps(),
+ display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(),
activeMode.fps);
if (displayId == mActiveDisplayId) {
@@ -1327,10 +1328,10 @@
const auto desiredActiveMode = display->getDesiredActiveMode();
const auto& modeOpt = desiredActiveMode->modeOpt;
const auto displayId = modeOpt->modePtr->getPhysicalDisplayId();
- const auto displayFps = modeOpt->modePtr->getFps();
+ const auto vsyncRate = modeOpt->modePtr->getVsyncRate();
const auto renderFps = modeOpt->fps;
clearDesiredActiveModeState(display);
- mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, displayFps);
+ mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, vsyncRate);
mScheduler->setRenderRate(displayId, renderFps);
if (displayId == mActiveDisplayId) {
@@ -1371,7 +1372,7 @@
}
ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(),
- to_string(displayModePtrOpt->get()->getFps()).c_str(),
+ to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(),
to_string(display->getId()).c_str());
if (display->getActiveMode() == desiredActiveMode->modeOpt) {
@@ -3211,6 +3212,7 @@
.setPhysicalDisplayId(displayId)
.setResolution({hwcMode.width, hwcMode.height})
.setVsyncPeriod(hwcMode.vsyncPeriod)
+ .setVrrConfig(hwcMode.vrrConfig)
.setDpiX(hwcMode.dpiX)
.setDpiY(hwcMode.dpiY)
.setGroup(hwcMode.configGroup)
@@ -3434,7 +3436,7 @@
if (const auto& physical = state.physical) {
const auto& mode = *physical->activeMode;
- display->setActiveMode(mode.getId(), mode.getFps(), mode.getFps());
+ display->setActiveMode(mode.getId(), mode.getVsyncRate(), mode.getVsyncRate());
}
display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack));
@@ -5142,7 +5144,8 @@
if (layer->setApi(s.api)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eSidebandStreamChanged) {
- if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ if (layer->setSidebandStream(s.sidebandStream, frameTimelineInfo, postTime))
+ flags |= eTraversalNeeded;
}
if (what & layer_state_t::eInputInfoChanged) {
layer->setInputInfo(*s.windowInfoHandle->getInfo());
@@ -5386,7 +5389,8 @@
if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eSidebandStreamChanged) {
- if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ if (layer->setSidebandStream(s.sidebandStream, frameTimelineInfo, postTime))
+ flags |= eTraversalNeeded;
}
if (what & layer_state_t::eDataspaceChanged) {
if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
@@ -5677,7 +5681,7 @@
display->setPowerMode(mode);
- const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getFps();
+ const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getVsyncRate();
if (!currentModeOpt || *currentModeOpt == hal::PowerMode::OFF) {
// Turn on the display
@@ -6385,6 +6389,7 @@
StringAppendF(&result, "Misc2FlagValue: %s (%s after boot)\n",
mMisc2FlagLateBootValue ? "true" : "false",
mMisc2FlagEarlyBootValue == mMisc2FlagLateBootValue ? "stable" : "modified");
+ StringAppendF(&result, "VrrConfigFlagValue: %s\n", mVrrConfigFlagValue ? "true" : "false");
getRenderEngine().dump(result);
@@ -6404,7 +6409,7 @@
std::string fps, xDpi, yDpi;
if (const auto activeModePtr =
display->refreshRateSelector().getActiveMode().modePtr.get()) {
- fps = to_string(activeModePtr->getFps());
+ fps = to_string(activeModePtr->getVsyncRate());
const auto dpi = activeModePtr->getDpi();
xDpi = base::StringPrintf("%.2f", dpi.x);
@@ -7967,7 +7972,7 @@
return snapshot.displayModes().get(defaultModeId);
})
.transform([](const DisplayModePtr& modePtr) {
- return scheduler::FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)};
+ return scheduler::FrameRateMode{modePtr->getPeakFps(), ftl::as_non_null(modePtr)};
});
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e22dd56..ef6b815 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1457,6 +1457,7 @@
bool mConnectedDisplayFlagValue;
bool mMisc2FlagEarlyBootValue;
bool mMisc2FlagLateBootValue;
+ bool mVrrConfigFlagValue;
};
class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 437fd35..c4077df 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -666,7 +666,7 @@
}
mRefreshRateSelector = std::make_shared<scheduler::RefreshRateSelector>(modes, kModeId60);
- const auto fps = mRefreshRateSelector->getActiveMode().modePtr->getFps();
+ const auto fps = mRefreshRateSelector->getActiveMode().modePtr->getVsyncRate();
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mRefreshRateStats =
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 9f0bdde..39a7ee5 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -153,7 +153,8 @@
native_handle_t* testHandle = native_handle_create(0, 1);
const bool ownsHandle = mFdp.ConsumeBool();
sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
- layer->setSidebandStream(nativeHandle);
+ layer->setSidebandStream(nativeHandle, getFuzzedFrameTimelineInfo(),
+ mFdp.ConsumeIntegral<nsecs_t>() /* postTime */);
layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
layer->fenceHasSignaled();
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 4d1a5ff..cbbfa16 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -390,7 +390,7 @@
PowerMode::OFF);
const auto fpsOpt = displayModes.get(modeId).transform(
- [](const DisplayModePtr& mode) { return mode->getFps(); });
+ [](const DisplayModePtr& mode) { return mode->getVsyncRate(); });
refreshRateStats.setRefreshRate(*fpsOpt);
refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes));
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index 6519d3a..bfc03aa 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -22,3 +22,11 @@
description: "This flag controls minor miscellaneous SurfaceFlinger changes. Cannot be read before boot finished!"
bug: "297389311"
}
+
+flag {
+ name: "vrr_config"
+ namespace: "core_graphics"
+ description: "Controls SurfaceFlinger support for VRR Configurations"
+ bug: "284845445"
+ is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 91c6239..9b46009 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -703,7 +703,7 @@
.setId(DisplayModeId(7))
.setVsyncPeriod(16666666)
.build();
- const Fps fps = mode->getFps() / 2;
+ const Fps fps = mode->getPeakFps() / 2;
mThread->onModeChanged({fps, ftl::as_non_null(mode)});
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, fps.getPeriodNsecs());
@@ -717,7 +717,7 @@
.setId(DisplayModeId(5))
.setVsyncPeriod(16666666)
.build();
- const Fps fps = mode->getFps() / 2;
+ const Fps fps = mode->getPeakFps() / 2;
mThread->onModeChanged({fps, ftl::as_non_null(mode)});
expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, fps.getPeriodNsecs());
@@ -731,7 +731,7 @@
.setId(DisplayModeId(7))
.setVsyncPeriod(16666666)
.build();
- const Fps fps = mode->getFps() / 2;
+ const Fps fps = mode->getPeakFps() / 2;
mThread->onModeChanged({fps, ftl::as_non_null(mode)});
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, fps.getPeriodNsecs());
}
@@ -748,7 +748,7 @@
.setId(DisplayModeId(9))
.setVsyncPeriod(16666666)
.build();
- const Fps fps = mode->getFps() / 2;
+ const Fps fps = mode->getPeakFps() / 2;
mThread->onModeChanged({fps, ftl::as_non_null(mode)});
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, fps.getPeriodNsecs());
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 50c1626..264b172 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -36,6 +36,9 @@
#include "libsurfaceflinger_unittest_main.h"
+#include <com_android_graphics_surfaceflinger_flags.h>
+
+using namespace com::android::graphics::surfaceflinger;
using namespace std::chrono_literals;
namespace android::scheduler {
@@ -48,6 +51,7 @@
using SetPolicyResult = RefreshRateSelector::SetPolicyResult;
using mock::createDisplayMode;
+using mock::createVrrDisplayMode;
struct TestableRefreshRateSelector : RefreshRateSelector {
using RefreshRateSelector::FrameRateRanking;
@@ -201,6 +205,19 @@
static inline const ftl::NonNull<DisplayModePtr> kMode10 =
ftl::as_non_null(createDisplayMode(kModeId10, 10_Hz));
+ // VRR modes
+ static inline const ftl::NonNull<DisplayModePtr> kVrrMode120TE240 = ftl::as_non_null(
+ createVrrDisplayMode(kModeId120, 240_Hz,
+ hal::VrrConfig{
+ .minFrameIntervalNs =
+ static_cast<Fps>(120_Hz).getPeriodNsecs()}));
+
+ static inline const ftl::NonNull<DisplayModePtr> kVrrMode60TE120 = ftl::as_non_null(
+ createVrrDisplayMode(kModeId60, 120_Hz,
+ hal::VrrConfig{.minFrameIntervalNs =
+ static_cast<Fps>(60_Hz).getPeriodNsecs()},
+ /*group=*/1));
+
// Test configurations.
static inline const DisplayModes kModes_60 = makeModes(kMode60);
static inline const DisplayModes kModes_35_60_90 = makeModes(kMode35, kMode60, kMode90);
@@ -225,6 +242,11 @@
static inline const DisplayModes kModes_1_5_10 = makeModes(kMode1, kMode5, kMode10);
static inline const DisplayModes kModes_60_90_120 = makeModes(kMode60, kMode90, kMode120);
+ // VRR display modes
+ static inline const DisplayModes kVrrMode_120 = makeModes(kVrrMode120TE240);
+ static inline const DisplayModes kVrrModes_60_120 =
+ makeModes(kVrrMode60TE120, kVrrMode120TE240);
+
// This is a typical TV configuration.
static inline const DisplayModes kModes_24_25_30_50_60_Frac =
makeModes(kMode24, kMode24Frac, kMode25, kMode30, kMode30Frac, kMode50, kMode60,
@@ -973,7 +995,8 @@
lr.desiredRefreshRate = Fps::fromValue(fps);
const auto mode = selector.getBestFrameRateMode(layers);
EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses "
- << to_string(mode->getFps());
+ << to_string(mode->getPeakFps()) << "("
+ << to_string(mode->getVsyncRate()) << ")";
}
}
@@ -988,7 +1011,8 @@
lr.desiredRefreshRate = Fps::fromValue(fps);
const auto mode = selector.getBestFrameRateMode(layers);
EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses "
- << to_string(mode->getFps());
+ << to_string(mode->getPeakFps()) << "("
+ << to_string(mode->getVsyncRate()) << ")";
}
}
@@ -1029,7 +1053,8 @@
lr.desiredRefreshRate = Fps::fromValue(fps);
const auto mode = selector.getBestFrameRateMode(layers, {});
EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses "
- << to_string(mode->getFps());
+ << to_string(mode->getPeakFps()) << "("
+ << to_string(mode->getVsyncRate()) << ")";
}
}
@@ -1146,9 +1171,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -1175,9 +1200,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -1207,9 +1232,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -1239,9 +1264,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -1267,9 +1292,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
std::tie(refreshRates, signals) =
@@ -1281,9 +1306,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1301,9 +1326,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
std::tie(refreshRates, signals) =
@@ -1326,9 +1351,9 @@
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
<< "Expected " << expectedRefreshRates[i].fps.getIntValue() << " ("
- << expectedRefreshRates[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRefreshRates[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << refreshRates[i].frameRateMode.fps.getIntValue() << " ("
- << refreshRates[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << refreshRates[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -1434,7 +1459,7 @@
layers[1].frameRateCategory = testCase.frameRateCategory;
}
- EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps())
+ EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps())
<< "did not get expected frame rate for " << lr.name;
}
}
@@ -1491,7 +1516,7 @@
layers[1].frameRateCategory = testCase.frameRateCategory;
}
- EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps())
+ EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps())
<< "did not get expected frame rate for " << lr.name;
}
}
@@ -1529,9 +1554,10 @@
ss << "ExplicitDefault " << desired;
lr.name = ss.str();
- const auto bestFps = selector.getBestFrameRateMode(layers)->getFps();
- EXPECT_EQ(expected, bestFps)
- << "expected " << expected << " for " << desired << " but got " << bestFps;
+ const auto bestMode = selector.getBestFrameRateMode(layers);
+ EXPECT_EQ(expected, bestMode->getPeakFps())
+ << "expected " << expected << " for " << desired << " but got "
+ << bestMode->getPeakFps() << "(" << bestMode->getVsyncRate() << ")";
}
}
@@ -1608,7 +1634,7 @@
ss << "ExplicitExact " << desired;
lr.name = ss.str();
- EXPECT_EQ(lr.desiredRefreshRate, selector.getBestFrameRateMode(layers)->getFps());
+ EXPECT_EQ(lr.desiredRefreshRate, selector.getBestFrameRateMode(layers)->getPeakFps());
}
}
}
@@ -1713,9 +1739,9 @@
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
<< "Expected " << expectedRanking[i].fps.getIntValue() << " ("
- << expectedRanking[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRanking[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << actualRanking[i].frameRateMode.fps.getIntValue() << " ("
- << actualRanking[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << actualRanking[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
lr1.vote = LayerVoteType::Max;
@@ -1755,9 +1781,9 @@
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
<< "Expected " << expectedRanking[i].fps.getIntValue() << " ("
- << expectedRanking[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRanking[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << actualRanking[i].frameRateMode.fps.getIntValue() << " ("
- << actualRanking[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << actualRanking[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
lr1.vote = LayerVoteType::Heuristic;
@@ -1795,9 +1821,9 @@
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
<< "Expected " << expectedRanking[i].fps.getIntValue() << " ("
- << expectedRanking[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRanking[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << actualRanking[i].frameRateMode.fps.getIntValue() << " ("
- << actualRanking[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << actualRanking[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
lr1.desiredRefreshRate = 120_Hz;
@@ -1838,9 +1864,9 @@
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
<< "Expected " << expectedRanking[i].fps.getIntValue() << " ("
- << expectedRanking[i].modePtr->getFps().getIntValue() << ")"
+ << expectedRanking[i].modePtr->getVsyncRate().getIntValue() << ")"
<< " Actual " << actualRanking[i].frameRateMode.fps.getIntValue() << " ("
- << actualRanking[i].frameRateMode.modePtr->getFps().getIntValue() << ")";
+ << actualRanking[i].frameRateMode.modePtr->getVsyncRate().getIntValue() << ")";
}
}
@@ -2485,7 +2511,8 @@
const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
layers[0].desiredRefreshRate = fps;
layers[0].vote = vote;
- EXPECT_EQ(fps.getIntValue(), selector.getBestFrameRateMode(layers)->getFps().getIntValue())
+ EXPECT_EQ(fps.getIntValue(),
+ selector.getBestFrameRateMode(layers)->getPeakFps().getIntValue())
<< "Failed for " << ftl::enum_string(vote);
};
@@ -2524,13 +2551,13 @@
},
};
- EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals)->getFps());
+ EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals)->getPeakFps());
}
TEST_P(RefreshRateSelectorTest, modeComparison) {
- EXPECT_LT(kMode60->getFps(), kMode90->getFps());
- EXPECT_GE(kMode60->getFps(), kMode60->getFps());
- EXPECT_GE(kMode90->getFps(), kMode90->getFps());
+ EXPECT_LT(kMode60->getPeakFps(), kMode90->getPeakFps());
+ EXPECT_GE(kMode60->getPeakFps(), kMode60->getPeakFps());
+ EXPECT_GE(kMode90->getPeakFps(), kMode90->getPeakFps());
}
TEST_P(RefreshRateSelectorTest, testKernelIdleTimerAction) {
@@ -2579,27 +2606,27 @@
auto selector = createSelector(kModes_30_60_72_90_120, kModeId30);
const auto frameRate = 30_Hz;
- Fps displayRefreshRate = selector.getActiveMode().getFps();
+ Fps displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(1, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
selector.setActiveMode(kModeId60, 60_Hz);
- displayRefreshRate = selector.getActiveMode().getFps();
+ displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(2, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
selector.setActiveMode(kModeId72, 72_Hz);
- displayRefreshRate = selector.getActiveMode().getFps();
+ displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
selector.setActiveMode(kModeId90, 90_Hz);
- displayRefreshRate = selector.getActiveMode().getFps();
+ displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(3, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
selector.setActiveMode(kModeId120, 120_Hz);
- displayRefreshRate = selector.getActiveMode().getFps();
+ displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
selector.setActiveMode(kModeId90, 90_Hz);
- displayRefreshRate = selector.getActiveMode().getFps();
+ displayRefreshRate = selector.getActiveMode().getPeakFps();
EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(24_Hz, 25_Hz));
@@ -3029,7 +3056,7 @@
for (size_t i = 0; i < expected.size(); i++) {
const auto [expectedRenderRate, expectedRefreshRate] = expected[i];
EXPECT_EQ(expectedRenderRate, primaryRefreshRates[i].fps);
- EXPECT_EQ(expectedRefreshRate, primaryRefreshRates[i].modePtr->getFps());
+ EXPECT_EQ(expectedRefreshRate, primaryRefreshRates[i].modePtr->getPeakFps());
}
}
@@ -3175,6 +3202,7 @@
}
// TODO(b/266481656): Once this bug is fixed, we can remove this test
+// And test for VRR when we remove this work around for VRR.
TEST_P(RefreshRateSelectorTest, noLowerFrameRateOnMinVote) {
auto selector = createSelector(kModes_60_90, kModeId60);
@@ -3304,5 +3332,187 @@
EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
}
+// VRR tests
+TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) {
+ return;
+ }
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ EXPECT_TRUE(selector.supportsFrameRateOverride());
+
+ const auto minRate = selector.getMinSupportedRefreshRate();
+ const auto performanceRate = selector.getMaxSupportedRefreshRate();
+ const auto minRateByPolicy = selector.getMinRefreshRateByPolicy();
+ const auto performanceRateByPolicy = selector.getMaxRefreshRateByPolicy();
+
+ EXPECT_EQ(kVrrMode120TE240, minRate);
+ EXPECT_EQ(kVrrMode120TE240, performanceRate);
+ EXPECT_EQ(kVrrMode120TE240, minRateByPolicy);
+ EXPECT_EQ(kVrrMode120TE240, performanceRateByPolicy);
+}
+
+TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) {
+ return;
+ }
+
+ auto selector = createSelector(kVrrModes_60_120, kModeId120);
+
+ const FpsRange only120 = {120_Hz, 120_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, only120}, {only120, only120}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 120_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range120 = {0_Hz, 120_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range120}, {only120, range120}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 120_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range90 = {0_Hz, 90_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range90}, {only120, range90}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 80_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range80 = {0_Hz, 80_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range80}, {only120, range80}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 80_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range60 = {0_Hz, 60_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range60}, {only120, range60}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 60_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range48 = {0_Hz, 48_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range48}, {only120, range48}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 48_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ const FpsRange range30 = {0_Hz, 30_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range30}, {only120, range30}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 30_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) {
+ return;
+ }
+
+ auto selector = createSelector(kVrrModes_60_120, kModeId120);
+
+ const FpsRange range120 = {0_Hz, 120_Hz};
+ const FpsRange range60 = {0_Hz, 60_Hz};
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {range120, range60}, {range120, range60}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 60_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId60, {range60, range60}, {range60, range60}}));
+ EXPECT_FRAME_RATE_MODE(kVrrMode60TE120, 60_Hz,
+ selector.getBestScoredFrameRate({}).frameRateMode);
+}
+
+TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) {
+ return;
+ }
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ // TODO(b/297600226) Run at lower than 30 Fps for dVRR
+ const std::vector<Fps> desiredRefreshRates = {30_Hz, 34.285_Hz, 40_Hz, 48_Hz,
+ 60_Hz, 80_Hz, 120_Hz};
+ const std::vector<LayerVoteType> layerVotes = {LayerVoteType::ExplicitDefault,
+ LayerVoteType::ExplicitExactOrMultiple,
+ LayerVoteType::ExplicitExact};
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].name = "Test layer";
+ layers[0].ownerUid = 1234;
+
+ for (auto desiredRefreshRate : desiredRefreshRates) {
+ layers[0].desiredRefreshRate = desiredRefreshRate;
+ for (auto vote : layerVotes) {
+ layers[0].vote = vote;
+ auto frameRateOverrides = selector.getFrameRateOverrides(layers, 240_Hz, {});
+ EXPECT_EQ(1u, frameRateOverrides.size());
+ ASSERT_EQ(1u, frameRateOverrides.count(1234));
+ EXPECT_EQ(desiredRefreshRate, frameRateOverrides.at(1234));
+ }
+ }
+}
+
+TEST_P(RefreshRateSelectorTest, renderFrameRatesForVrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) {
+ return;
+ }
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ const FpsRange only120 = {120_Hz, 120_Hz};
+ const FpsRange range120 = {0_Hz, 120_Hz};
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {only120, range120}, {only120, range120}}));
+
+ std::vector<Fps> expected = {20_Hz, 21.818_Hz, 24_Hz, 26.666_Hz, 30_Hz, 34.285_Hz,
+ 40_Hz, 48_Hz, 60_Hz, 80_Hz, 120_Hz};
+
+ auto primaryRefreshRates = selector.getPrimaryFrameRates();
+ ASSERT_EQ(expected.size(), primaryRefreshRates.size());
+
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i], primaryRefreshRates[i].fps);
+ EXPECT_EQ(120_Hz, primaryRefreshRates[i].modePtr->getPeakFps());
+ }
+
+ // Render range (0,90)
+ const FpsRange range90 = {0_Hz, 90_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {range120, range90}, {range120, range90}}));
+
+ expected = {20_Hz, 21.818_Hz, 24_Hz, 26.666_Hz, 30_Hz, 34.285_Hz, 40_Hz, 48_Hz, 60_Hz, 80_Hz};
+
+ primaryRefreshRates = selector.getPrimaryFrameRates();
+ ASSERT_EQ(expected.size(), primaryRefreshRates.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i], primaryRefreshRates[i].fps);
+ EXPECT_EQ(120_Hz, primaryRefreshRates[i].modePtr->getPeakFps());
+ }
+
+ // Render range (0,60)
+ const FpsRange range60 = {0_Hz, 60_Hz};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {kModeId120, {range120, range60}, {range120, range60}}));
+ expected = {20_Hz, 21.818_Hz, 24_Hz, 26.666_Hz, 30_Hz, 34.285_Hz, 40_Hz, 48_Hz, 60_Hz};
+
+ primaryRefreshRates = selector.getPrimaryFrameRates();
+ ASSERT_EQ(expected.size(), primaryRefreshRates.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i], primaryRefreshRates[i].fps);
+ EXPECT_EQ(120_Hz, primaryRefreshRates[i].modePtr->getPeakFps());
+ }
+}
} // namespace
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8458aa3..908c9ab 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -997,7 +997,7 @@
const auto activeMode = modes.get(activeModeId);
LOG_ALWAYS_FATAL_IF(!activeMode);
- const auto fps = activeMode->get()->getFps();
+ const auto fps = activeMode->get()->getPeakFps();
state.physical = {.id = physicalId,
.hwcDisplayId = *mHwcDisplayId,
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index 108151e..1cf14ae 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -127,7 +127,7 @@
sp<NativeHandle> stream =
NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
false);
- layer->setSidebandStream(stream);
+ layer->setSidebandStream(stream, FrameTimelineInfo{}, 20);
mFlinger.mutableCurrentState().layersSortedByZ.add(layer);
mTunnelModeEnabledReporter->updateTunnelModeStatus();
mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
@@ -151,7 +151,7 @@
sp<NativeHandle> stream =
NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
false);
- layerWithSidebandStream->setSidebandStream(stream);
+ layerWithSidebandStream->setSidebandStream(stream, FrameTimelineInfo{}, 20);
mFlinger.mutableCurrentState().layersSortedByZ.add(simpleLayer);
mFlinger.mutableCurrentState().layersSortedByZ.add(layerWithSidebandStream);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
index 3b36361..cb05c00 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h
@@ -20,17 +20,23 @@
namespace android::mock {
-inline DisplayModePtr createDisplayMode(
- DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
+inline DisplayMode::Builder createDisplayModeBuilder(
+ DisplayModeId modeId, Fps displayRefreshRate, int32_t group = 0,
ui::Size resolution = ui::Size(1920, 1080),
PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0)) {
return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
.setId(modeId)
.setPhysicalDisplayId(displayId)
- .setVsyncPeriod(refreshRate.getPeriodNsecs())
+ .setVsyncPeriod(displayRefreshRate.getPeriodNsecs())
.setGroup(group)
- .setResolution(resolution)
- .build();
+ .setResolution(resolution);
+}
+
+inline DisplayModePtr createDisplayMode(
+ DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
+ ui::Size resolution = ui::Size(1920, 1080),
+ PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0)) {
+ return createDisplayModeBuilder(modeId, refreshRate, group, resolution, displayId).build();
}
inline DisplayModePtr createDisplayMode(PhysicalDisplayId displayId, DisplayModeId modeId,
@@ -38,11 +44,19 @@
return createDisplayMode(modeId, refreshRate, {}, {}, displayId);
}
+inline DisplayModePtr createVrrDisplayMode(
+ DisplayModeId modeId, Fps displayRefreshRate, hal::VrrConfig vrrConfig, int32_t group = 0,
+ ui::Size resolution = ui::Size(1920, 1080),
+ PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0)) {
+ return createDisplayModeBuilder(modeId, displayRefreshRate, group, resolution, displayId)
+ .setVrrConfig(std::move(vrrConfig))
+ .build();
+}
inline DisplayModePtr cloneForDisplay(PhysicalDisplayId displayId, const DisplayModePtr& modePtr) {
return DisplayMode::Builder(modePtr->getHwcId())
.setId(modePtr->getId())
.setPhysicalDisplayId(displayId)
- .setVsyncPeriod(modePtr->getVsyncPeriod())
+ .setVsyncPeriod(modePtr->getVsyncRate().getPeriodNsecs())
.setGroup(modePtr->getGroup())
.setResolution(modePtr->getResolution())
.build();
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h
index 4cfdd58..bfcdd9b 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h
@@ -19,7 +19,7 @@
#include <scheduler/FrameRateMode.h>
// Use a C style macro to keep the line numbers printed in gtest
-#define EXPECT_FRAME_RATE_MODE(_modePtr, _fps, _mode) \
- EXPECT_EQ((scheduler::FrameRateMode{(_fps), (_modePtr)}), (_mode)) \
- << "Expected " << (_fps) << " (" << (_modePtr)->getFps() << ") but was " \
- << (_mode).fps << " (" << (_mode).modePtr->getFps() << ")"
+#define EXPECT_FRAME_RATE_MODE(_modePtr, _fps, _mode) \
+ EXPECT_EQ((scheduler::FrameRateMode{(_fps), (_modePtr)}), (_mode)) \
+ << "Expected " << (_fps) << " (" << (_modePtr)->getVsyncRate() << ") but was " \
+ << (_mode).fps << " (" << (_mode).modePtr->getVsyncRate() << ")"
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 7159d83..c5870d4 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1565,22 +1565,26 @@
query_value);
return VK_ERROR_SURFACE_LOST_KHR;
}
- uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
- const auto mailbox_num_images = std::max(3u, create_info->minImageCount);
- const auto requested_images =
- swap_interval ? create_info->minImageCount : mailbox_num_images;
- uint32_t num_images = requested_images - 1 + min_undequeued_buffers;
+ const uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
// Lower layer insists that we have at least min_undequeued_buffers + 1
// buffers. This is wasteful and we'd like to relax it in the shared case,
// but not all the pieces are in place for that to work yet. Note we only
// lie to the lower layer--we don't want to give the app back a swapchain
// with extra images (which they can't actually use!).
- uint32_t min_buffer_count = min_undequeued_buffers + 1;
- err = native_window_set_buffer_count(
- window, std::max(min_buffer_count, num_images));
+ const uint32_t min_buffer_count = min_undequeued_buffers + 1;
+
+ uint32_t num_images;
+ if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
+ num_images = std::max(3u, create_info->minImageCount);
+ } else {
+ num_images = create_info->minImageCount;
+ }
+
+ const uint32_t buffer_count = std::max(min_buffer_count, num_images);
+ err = native_window_set_buffer_count(window, buffer_count);
if (err != android::OK) {
- ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
+ ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", buffer_count,
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}