Merge "Clear unexpected buffer handle of sideband layer" into main
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e2a2927..073d0c4 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -250,12 +250,18 @@
// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined
// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here.
-#define ENFORCE_VALID_USER(userId) \
- { \
- if (static_cast<uid_t>(std::abs(userId)) >= \
- std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) { \
- return error("userId invalid: " + std::to_string(userId)); \
- } \
+#define ENFORCE_VALID_USER(userId) \
+ { \
+ if (static_cast<uid_t>(userId) >= std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) { \
+ return error("userId invalid: " + std::to_string(userId)); \
+ } \
+ }
+
+#define ENFORCE_VALID_USER_OR_NULL(userId) \
+ { \
+ if (static_cast<uid_t>(userId) != USER_NULL) { \
+ ENFORCE_VALID_USER(userId); \
+ } \
}
#define CHECK_ARGUMENT_UUID(uuid) { \
@@ -751,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);
@@ -761,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);
@@ -799,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) {
@@ -823,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) {
@@ -886,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(
@@ -904,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();
@@ -1833,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;
@@ -3841,7 +3860,7 @@
int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
const std::optional<std::string>& dexMetadata, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
- ENFORCE_VALID_USER(userId);
+ ENFORCE_VALID_USER_OR_NULL(userId);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
LOCK_PACKAGE_USER();
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_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/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
index 96092b1..690c39a 100644
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
@@ -36,8 +36,8 @@
triage_assignee: "waghpawan@google.com",
// This fuzzer should be used only test fuzzService locally
- fuzz_on_haiku_host: true,
- fuzz_on_haiku_device: true,
+ fuzz_on_haiku_host: false,
+ fuzz_on_haiku_device: false,
},
}
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
index c447bff..5d68fe1 100755
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
@@ -30,7 +30,7 @@
for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER DUMP SHELL_CMD; do
echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE"
- ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT"
+ ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=60 &>"$FUZZER_OUT"
echo "INFO: Searching fuzzer output for expected crashes"
if grep -q "Expected crash, $CRASH_TYPE." "$FUZZER_OUT"
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/gui/Android.bp b/libs/gui/Android.bp
index 298838d..2ea4d16 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -192,6 +192,18 @@
},
}
+aconfig_declarations {
+ name: "libgui_flags",
+ package: "com.android.graphics.libgui.flags",
+ srcs: ["libgui_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "libguiflags",
+ vendor_available: true,
+ aconfig_declarations: "libgui_flags",
+}
+
cc_library_shared {
name: "libgui",
vendor_available: true,
@@ -206,6 +218,7 @@
static_libs: [
"libgui_aidl_static",
"libgui_window_info_static",
+ "libguiflags",
],
export_static_lib_headers: [
"libgui_aidl_static",
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
new file mode 100644
index 0000000..a16be78
--- /dev/null
+++ b/libs/gui/libgui_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.graphics.libgui.flags"
+
+flag {
+ name: "bq_setframerate"
+ namespace: "core_graphics"
+ description: "This flag controls plumbing setFrameRate thru BufferQueue"
+ bug: "281695725"
+ is_fixed_read_only: true
+}
+
diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp
index b5a5e72..c8d1da7 100644
--- a/libs/input/MotionPredictor.cpp
+++ b/libs/input/MotionPredictor.cpp
@@ -181,7 +181,8 @@
int64_t predictionTime = mBuffers->lastTimestamp();
const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos;
- for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) {
+ for (size_t i = 0; i < static_cast<size_t>(predictedR.size()) && predictionTime <= futureTime;
+ ++i) {
if (predictedR[i] < mModel->config().distanceNoiseFloor) {
// Stop predicting when the predicted output is below the model's noise floor.
//
@@ -198,7 +199,7 @@
const TfLiteMotionPredictorSample::Point predictedPoint =
convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]);
- ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, predictedPoint.x, predictedPoint.y);
+ ALOGD_IF(isDebug(), "prediction %zu: %f, %f", i, predictedPoint.x, predictedPoint.y);
PointerCoords coords;
coords.clear();
coords.setAxisValue(AMOTION_EVENT_AXIS_X, predictedPoint.x);
diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp
index 5984b4d3..d17476e 100644
--- a/libs/input/TfLiteMotionPredictor.cpp
+++ b/libs/input/TfLiteMotionPredictor.cpp
@@ -143,8 +143,7 @@
tensor->name, TfLiteTypeGetName(tensor->type), TfLiteTypeGetName(type));
LOG_ALWAYS_FATAL_IF(!tensor->data.data);
- return {reinterpret_cast<T*>(tensor->data.data),
- static_cast<typename std::span<T>::index_type>(tensor->bytes / sizeof(T))};
+ return std::span<T>(reinterpret_cast<T*>(tensor->data.data), tensor->bytes / sizeof(T));
}
// Verifies that a tensor exists and has an underlying buffer of type T.
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 1f29a00..2af5a4a 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -13,3 +13,10 @@
description: "Set to true to enable crashing whenever bad inbound events are going into InputDispatcher"
bug: "271455682"
}
+
+flag {
+ name: "enable_pointer_choreographer"
+ namespace: "input"
+ description: "Set to true to enable PointerChoreographer: the new pipeline for showing pointer icons"
+ bug: "293587049"
+}
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
index e269f0d..3f77c78 100644
--- a/libs/nativewindow/include/android/hardware_buffer_aidl.h
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -95,14 +95,22 @@
binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
reset();
- return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ if (__builtin_available(android __ANDROID_API_U__, *)) {
+ return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ } else {
+ return STATUS_FAILED_TRANSACTION;
+ }
}
binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
if (!mBuffer) {
return STATUS_BAD_VALUE;
}
- return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ if (__builtin_available(android __ANDROID_API_U__, *)) {
+ return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ } else {
+ return STATUS_FAILED_TRANSACTION;
+ }
}
/**
@@ -150,9 +158,13 @@
if (!mBuffer) {
return "<HardwareBuffer: Invalid>";
}
- uint64_t id = 0;
- AHardwareBuffer_getId(mBuffer, &id);
- return "<HardwareBuffer " + std::to_string(id) + ">";
+ if (__builtin_available(android __ANDROID_API_S__, *)) {
+ uint64_t id = 0;
+ AHardwareBuffer_getId(mBuffer, &id);
+ return "<HardwareBuffer " + std::to_string(id) + ">";
+ } else {
+ return "<HardwareBuffer (unknown)>";
+ }
}
private:
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index b21b01c..48dc77e 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -31,14 +31,17 @@
#include "SkRect.h"
#include "SkTypeface.h"
#include "src/utils/SkMultiPictureDocument.h"
+#include <sys/stat.h>
namespace android {
namespace renderengine {
namespace skia {
// The root of the filename to write a recorded SKP to. In order for this file to
-// be written to /data/user/, user must run 'adb shell setenforce 0' on the device.
-static const std::string CAPTURED_FILENAME_BASE = "/data/user/re_skiacapture";
+// be written, user must run 'adb shell setenforce 0' on the device. Note: This
+// is handled by record.sh. FIXME(b/296282988): With updated selinux policies,
+// 'adb shell setenforce 0' should be unnecessary.
+static const std::string CAPTURED_FILE_DIR = "/data/misc/mskps";
SkiaCapture::~SkiaCapture() {
mTimer.stop();
@@ -169,11 +172,12 @@
ATRACE_CALL();
ALOGD("Set up multi-frame capture, ms = %llu", mTimerInterval.count());
base::SetProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_FILENAME, "");
- const std::scoped_lock lock(mMutex);
- // Attach a timestamp to the file.
+ mkdir(CAPTURED_FILE_DIR.c_str(), 0700);
+
+ const std::scoped_lock lock(mMutex);
mCaptureFile.clear();
- base::StringAppendF(&mCaptureFile, "%s_%lld.mskp", CAPTURED_FILENAME_BASE.c_str(),
+ base::StringAppendF(&mCaptureFile, "%s/re_skiacapture_%lld.mskp", CAPTURED_FILE_DIR.c_str(),
std::chrono::steady_clock::now().time_since_epoch().count());
auto stream = std::make_unique<SkFILEWStream>(mCaptureFile.c_str());
// We own this stream and need to hold it until close() finishes.
diff --git a/libs/renderengine/skia/debug/record.sh b/libs/renderengine/skia/debug/record.sh
index c818c40..88d8b09 100755
--- a/libs/renderengine/skia/debug/record.sh
+++ b/libs/renderengine/skia/debug/record.sh
@@ -43,7 +43,6 @@
# There is no guarantee that at least one frame passed through renderengine during that time
# but as far as I know it always at least writes a 0-byte file with a new name, unless it crashes
# the process it is recording.
-# /data/user/re_skiacapture_56204430551705.mskp
spin() {
case "$spin" in
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index 9a6bb7a..ee605c2 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -35,6 +35,7 @@
namespace angle {
+constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so";
constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW;
static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr;
@@ -115,8 +116,6 @@
android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
void* so = nullptr;
if (ns) {
- // Loading from an APK, so hard-code the suffix to "_angle".
- constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so";
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
@@ -130,19 +129,11 @@
}
} else {
// If we are here, ANGLE is loaded as built-in gl driver in the sphal.
- // Get the specified ANGLE library filename suffix.
- std::string angleEs2LibSuffix = android::base::GetProperty("ro.hardware.egl", "");
- if (angleEs2LibSuffix.empty()) {
- ALOGE("%s failed to get valid ANGLE library filename suffix!", __FUNCTION__);
- return false;
- }
-
- std::string angleEs2LibName = "libGLESv2_" + angleEs2LibSuffix + ".so";
- so = android_load_sphal_library(angleEs2LibName.c_str(), kAngleDlFlags);
+ so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags);
if (so) {
- ALOGD("dlopen (%s) success at %p", angleEs2LibName.c_str(), so);
+ ALOGD("dlopen (%s) success at %p", kAngleEs2Lib, so);
} else {
- ALOGE("%s failed to dlopen %s!", __FUNCTION__, angleEs2LibName.c_str());
+ ALOGE("%s failed to dlopen %s: %s!", __FUNCTION__, kAngleEs2Lib, dlerror());
return false;
}
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 0567a32..92c65e1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -27,10 +27,13 @@
#include <android/binder_interface_utils.h>
#include <android/sysprop/InputProperties.sysprop.h>
#include <binder/IPCThreadState.h>
+#include <com_android_input_flags.h>
#include <inputflinger_bootstrap.rs.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
+namespace input_flags = com::android::input::flags;
+
namespace android {
namespace {
@@ -38,8 +41,7 @@
const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
-const bool ENABLE_POINTER_CHOREOGRAPHER =
- sysprop::InputProperties::enable_pointer_choreographer().value_or(false);
+const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
int32_t exceptionCodeFromStatusT(status_t status) {
switch (status) {
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/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 962dc09..1e5a6fb 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -145,7 +145,8 @@
}
void LayerHierarchy::dump(std::ostream& out, const std::string& prefix,
- LayerHierarchy::Variant variant, bool isLastChild) const {
+ LayerHierarchy::Variant variant, bool isLastChild,
+ bool includeMirroredHierarchy) const {
if (!mLayer) {
out << " ROOT";
} else {
@@ -153,8 +154,11 @@
if (variant == LayerHierarchy::Variant::Relative) {
out << "(Relative) ";
} else if (variant == LayerHierarchy::Variant::Mirror) {
- out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ...";
- return;
+ if (!includeMirroredHierarchy) {
+ out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ...";
+ return;
+ }
+ out << "(Mirroring) ";
}
out << *mLayer;
}
@@ -168,7 +172,7 @@
childPrefix += (isLastChild ? " " : "│ ");
}
out << "\n";
- child->dump(out, childPrefix, childVariant, lastChild);
+ child->dump(out, childPrefix, childVariant, lastChild, includeMirroredHierarchy);
}
return;
}
@@ -435,8 +439,11 @@
std::stringstream ss;
ss << "TraversalPath{.id = " << id;
- if (mirrorRootId != UNASSIGNED_LAYER_ID) {
- ss << ", .mirrorRootId=" << mirrorRootId;
+ if (!mirrorRootIds.empty()) {
+ ss << ", .mirrorRootIds=";
+ for (auto rootId : mirrorRootIds) {
+ ss << rootId << ",";
+ }
}
if (!relativeRootIds.empty()) {
@@ -453,13 +460,6 @@
return ss.str();
}
-LayerHierarchy::TraversalPath LayerHierarchy::TraversalPath::getMirrorRoot() const {
- LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!isClone(), "Cannot get mirror root of a non cloned node");
- TraversalPath mirrorRootPath = *this;
- mirrorRootPath.id = mirrorRootId;
- return mirrorRootPath;
-}
-
// Helper class to update a passed in TraversalPath when visiting a child. When the object goes out
// of scope the TraversalPath is reset to its original state.
LayerHierarchy::ScopedAddToTraversalPath::ScopedAddToTraversalPath(TraversalPath& traversalPath,
@@ -471,7 +471,7 @@
traversalPath.id = layerId;
traversalPath.variant = variant;
if (variant == LayerHierarchy::Variant::Mirror) {
- traversalPath.mirrorRootId = mParentPath.id;
+ traversalPath.mirrorRootIds.emplace_back(mParentPath.id);
} else if (variant == LayerHierarchy::Variant::Relative) {
if (std::find(traversalPath.relativeRootIds.begin(), traversalPath.relativeRootIds.end(),
layerId) != traversalPath.relativeRootIds.end()) {
@@ -486,7 +486,7 @@
// Reset the traversal id to its original parent state using the state that was saved in
// the constructor.
if (mTraversalPath.variant == LayerHierarchy::Variant::Mirror) {
- mTraversalPath.mirrorRootId = mParentPath.mirrorRootId;
+ mTraversalPath.mirrorRootIds.pop_back();
} else if (mTraversalPath.variant == LayerHierarchy::Variant::Relative) {
mTraversalPath.relativeRootIds.pop_back();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 1e48387..ba2e262 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -57,25 +57,25 @@
// ├─ B {Traversal path id = 2}
// │ ├─ C {Traversal path id = 3}
// │ ├─ D {Traversal path id = 4}
- // │ └─ E {Traversal path id = 5}
- // ├─ F (Mirrors B) {Traversal path id = 6}
- // └─ G (Mirrors F) {Traversal path id = 7}
+ // │ └─ E (Mirrors C) {Traversal path id = 5}
+ // └─ F (Mirrors B) {Traversal path id = 6}
//
- // C, D and E can be traversed via B or via F then B or via G then F then B.
+ // C can be traversed via B or E or F and or via F then E.
// Depending on how the node is reached, its properties such as geometry or visibility might be
// different. And we can uniquely identify the node by keeping track of the nodes leading up to
// it. But to be more efficient we only need to track the nodes id and the top mirror root path.
// So C for example, would have the following unique traversal paths:
// - {Traversal path id = 3}
- // - {Traversal path id = 3, mirrorRootId = 6}
- // - {Traversal path id = 3, mirrorRootId = 7}
+ // - {Traversal path id = 3, mirrorRootIds = 5}
+ // - {Traversal path id = 3, mirrorRootIds = 6}
+ // - {Traversal path id = 3, mirrorRootIds = 6, 5}
struct TraversalPath {
uint32_t id;
LayerHierarchy::Variant variant;
// Mirrored layers can have a different geometry than their parents so we need to track
// the mirror roots in the traversal.
- uint32_t mirrorRootId = UNASSIGNED_LAYER_ID;
+ ftl::SmallVector<uint32_t, 5> mirrorRootIds;
// Relative layers can be visited twice, once by their parent and then once again by
// their relative parent. We keep track of the roots here to detect any loops in the
// hierarchy. If a relative root already exists in the list while building the
@@ -93,11 +93,10 @@
// Returns true if the node or its parents are not Detached.
bool isAttached() const { return !detached; }
// Returns true if the node is a clone.
- bool isClone() const { return mirrorRootId != UNASSIGNED_LAYER_ID; }
- TraversalPath getMirrorRoot() const;
+ bool isClone() const { return !mirrorRootIds.empty(); }
bool operator==(const TraversalPath& other) const {
- return id == other.id && mirrorRootId == other.mirrorRootId;
+ return id == other.id && mirrorRootIds == other.mirrorRootIds;
}
std::string toString() const;
@@ -107,8 +106,8 @@
struct TraversalPathHash {
std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
uint32_t hashCode = key.id * 31;
- if (key.mirrorRootId != UNASSIGNED_LAYER_ID) {
- hashCode += key.mirrorRootId * 31;
+ for (uint32_t mirrorRootId : key.mirrorRootIds) {
+ hashCode += mirrorRootId * 31;
}
return std::hash<size_t>{}(hashCode);
}
@@ -158,9 +157,17 @@
const LayerHierarchy* getParent() const;
friend std::ostream& operator<<(std::ostream& os, const LayerHierarchy& obj) {
std::string prefix = " ";
- obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false);
+ obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
+ /*includeMirroredHierarchy*/ false);
return os;
}
+ std::string dump() const {
+ std::string prefix = " ";
+ std::ostringstream os;
+ dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
+ /*includeMirroredHierarchy*/ true);
+ return os.str();
+ }
std::string getDebugStringShort() const;
// Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
@@ -178,7 +185,7 @@
void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant,
- bool isLastChild) const;
+ bool isLastChild, bool includeMirroredHierarchy) const;
const RequestedLayerState* mLayer;
LayerHierarchy* mParent = nullptr;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 80bedf4..899d2de 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -294,8 +294,11 @@
std::ostream& operator<<(std::ostream& out, const LayerSnapshot& obj) {
out << "Layer [" << obj.path.id;
- if (obj.path.mirrorRootId != UNASSIGNED_LAYER_ID) {
- out << " mirrored from " << obj.path.mirrorRootId;
+ if (!obj.path.mirrorRootIds.empty()) {
+ out << " mirrored from ";
+ for (auto rootId : obj.path.mirrorRootIds) {
+ out << rootId << ",";
+ }
}
out << "] " << obj.name << "\n " << (obj.isVisible ? "visible" : "invisible")
<< " reason=" << obj.getIsVisibleReason();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 047d376..2684000 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2648,7 +2648,7 @@
void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom, uint32_t mirrorRootId) {
mSnapshot->path.id = clonedFrom->getSequence();
- mSnapshot->path.mirrorRootId = mirrorRootId;
+ mSnapshot->path.mirrorRootIds.emplace_back(mirrorRootId);
cloneDrawingState(clonedFrom.get());
mClonedFrom = clonedFrom;
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index a0024d5..97c4145 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -345,7 +345,7 @@
}
int32_t LayerFE::getSequence() const {
- return mSnapshot->sequence;
+ return static_cast<int32_t>(mSnapshot->uniqueSequence);
}
bool LayerFE::hasRoundedCorners() const {
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/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index e4df494..551d744 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -294,7 +294,7 @@
if (mLayerVote.category != FrameRateCategory::Default) {
ALOGV("%s uses frame rate category: %d", mName.c_str(),
static_cast<int>(mLayerVote.category));
- votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, mLayerVote.fps,
+ votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, Fps(),
Seamlessness::Default, mLayerVote.category});
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 7e77bbe..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);
@@ -501,6 +516,12 @@
break;
case LayerVoteType::ExplicitCategory:
explicitCategoryVoteLayers++;
+ if (layer.frameRateCategory == FrameRateCategory::NoPreference) {
+ // Count this layer for Min vote as well. The explicit vote avoids
+ // touch boost and idle for choosing a category, while Min vote is for correct
+ // behavior when all layers are Min or no vote.
+ minVoteLayers++;
+ }
break;
case LayerVoteType::Heuristic:
break;
@@ -617,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) &&
@@ -658,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;
}
}
@@ -693,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);
}();
@@ -709,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
@@ -836,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/;
@@ -927,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();
@@ -938,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 {
@@ -964,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;
}
@@ -1047,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});
};
@@ -1128,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();
@@ -1155,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);
}
}
@@ -1165,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;
}
@@ -1278,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);
@@ -1334,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 4adcd55..1a08244 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -497,6 +497,8 @@
// Trunk-Stable flags
mMiscFlagValue = flags::misc1();
mConnectedDisplayFlagValue = flags::connected_display();
+ mMisc2FlagEarlyBootValue = flags::late_boot_misc2();
+ mVrrConfigFlagValue = flags::vrr_config();
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -740,6 +742,8 @@
}));
LOG_ALWAYS_FATAL_IF(flags::misc1() != mMiscFlagValue, "misc1 flag is not boot stable!");
+
+ mMisc2FlagLateBootValue = flags::late_boot_misc2();
}
static std::optional<renderengine::RenderEngine::RenderEngineType>
@@ -1040,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));
@@ -1061,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);
@@ -1196,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.
@@ -1250,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(),
@@ -1299,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) {
@@ -1324,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) {
@@ -1368,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) {
@@ -3208,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)
@@ -3431,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));
@@ -5676,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
@@ -5825,6 +5830,7 @@
{"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
{"--vsync"s, dumper(&SurfaceFlinger::dumpVsync)},
{"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+ {"--frontend"s, dumper(&SurfaceFlinger::dumpFrontEnd)},
};
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
@@ -6134,6 +6140,38 @@
}
}
+void SurfaceFlinger::dumpFrontEnd(std::string& result) {
+ mScheduler
+ ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
+ std::ostringstream out;
+ out << "\nComposition list\n";
+ ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) {
+ if (lastPrintedLayerStackHeader != snapshot->outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot->outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << *snapshot << "\n";
+ }
+
+ out << "\nInput list\n";
+ lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK;
+ mLayerSnapshotBuilder.forEachInputSnapshot(
+ [&](const frontend::LayerSnapshot& snapshot) {
+ if (lastPrintedLayerStackHeader != snapshot.outputFilter.layerStack) {
+ lastPrintedLayerStackHeader = snapshot.outputFilter.layerStack;
+ out << "LayerStack=" << lastPrintedLayerStackHeader.id << "\n";
+ }
+ out << " " << snapshot << "\n";
+ });
+
+ out << "\nLayer Hierarchy\n"
+ << mLayerHierarchyBuilder.getHierarchy().dump() << "\n\n";
+ result.append(out.str());
+ })
+ .get();
+}
+
perfetto::protos::LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
std::unordered_set<uint64_t> stackIdsToSkip;
@@ -6348,6 +6386,10 @@
StringAppendF(&result, "MiscFlagValue: %s\n", mMiscFlagValue ? "true" : "false");
StringAppendF(&result, "ConnectedDisplayFlagValue: %s\n",
mConnectedDisplayFlagValue ? "true" : "false");
+ 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);
@@ -6367,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);
@@ -7930,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 59b1172..ef6b815 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1090,6 +1090,7 @@
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
void dumpHdrInfo(std::string& result) const REQUIRES(mStateLock);
+ void dumpFrontEnd(std::string& result);
perfetto::protos::LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(perfetto::protos::LayersProto& layersProto,
@@ -1454,6 +1455,9 @@
// Trunk-Stable flags
bool mMiscFlagValue;
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_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 f47ed45..bfc03aa 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -15,3 +15,18 @@
bug: "278199093"
is_fixed_read_only: true
}
+
+flag{
+ name: "late_boot_misc2"
+ namespace: "core_graphics"
+ 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/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index e4f49e8..95f1940 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -736,4 +736,22 @@
EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
}
+TEST_F(LayerHierarchyTest, canMirrorDisplayWithMirrors) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ reparentLayer(12, UNASSIGNED_LAYER_ID);
+ mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expected = {1, 11, 111, 13, 14, 11, 111, 2, 3,
+ 1, 11, 111, 13, 14, 11, 111, 2};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expected);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expected);
+ expected = {12, 121, 122, 1221};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b67494f..b7996ce 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -529,7 +529,7 @@
EXPECT_EQ(1, frequentLayerCount(time));
// First LayerRequirement is the layer's category specification
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
// Second LayerRequirement is the frame rate specification
@@ -544,7 +544,7 @@
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
}
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index e0133d6..11072bc 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -223,8 +223,6 @@
}
TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) {
- // When a layer only has a category set, the LayerVoteType should be the LayerInfo's default.
- // The most common case should be Heuristic.
LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
.category = FrameRateCategory::High};
layerInfo.setLayerVote(vote);
@@ -234,6 +232,20 @@
ASSERT_EQ(actualVotes.size(), 1u);
ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
ASSERT_EQ(actualVotes[0].category, vote.category);
+ ASSERT_EQ(actualVotes[0].fps, 0_Hz);
+}
+
+TEST_F(LayerInfoTest, getRefreshRateVote_categoryNoPreference) {
+ LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
+ .category = FrameRateCategory::NoPreference};
+ layerInfo.setLayerVote(vote);
+
+ auto actualVotes =
+ layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
+ ASSERT_EQ(actualVotes.size(), 1u);
+ ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
+ ASSERT_EQ(actualVotes[0].category, vote.category);
+ ASSERT_EQ(actualVotes[0].fps, 0_Hz);
}
TEST_F(LayerInfoTest, getRefreshRateVote_noData) {
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2353480..1227b99 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -410,8 +410,8 @@
std::vector<uint32_t> expected = {1, 11, 111, 13, 2, 3, 1, 11, 111,
13, 2, 4, 1, 11, 111, 13, 2};
UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
- EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootId = 3})->outputFilter.layerStack.id, 3u);
- EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootId = 4})->outputFilter.layerStack.id, 4u);
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 3u})->outputFilter.layerStack.id, 3u);
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 4u})->outputFilter.layerStack.id, 4u);
}
// ROOT (DISPLAY 0)
@@ -435,7 +435,7 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
EXPECT_TRUE(getSnapshot({.id = 111})->inputInfo.touchableRegion.hasSameRects(touch));
Region touchCroppedByMirrorRoot{Rect{0, 0, 50, 50}};
- EXPECT_TRUE(getSnapshot({.id = 111, .mirrorRootId = 3})
+ EXPECT_TRUE(getSnapshot({.id = 111, .mirrorRootIds = 3u})
->inputInfo.touchableRegion.hasSameRects(touchCroppedByMirrorRoot));
}
@@ -462,6 +462,21 @@
EXPECT_EQ(startingNumSnapshots, mSnapshotBuilder.getSnapshots().size());
}
+TEST_F(LayerSnapshotTest, canMirrorDisplayWithMirrors) {
+ reparentLayer(12, UNASSIGNED_LAYER_ID);
+ mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11);
+ std::vector<uint32_t> expected = {1, 11, 111, 13, 14, 11, 111, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 3);
+ expected = {1, 11, 111, 13, 14, 11, 111, 2, 3, 1, 11, 111, 13, 14, 11, 111, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+ EXPECT_EQ(getSnapshot({.id = 11, .mirrorRootIds = 14u})->outputFilter.layerStack.id, 0u);
+ EXPECT_EQ(getSnapshot({.id = 11, .mirrorRootIds = 3u})->outputFilter.layerStack.id, 3u);
+ EXPECT_EQ(getSnapshot({.id = 11, .mirrorRootIds = 3u, 14u})->outputFilter.layerStack.id, 3u);
+}
+
// Rel z doesn't create duplicate snapshots but this is for completeness
TEST_F(LayerSnapshotTest, cleanUpUnreachableSnapshotsAfterRelZ) {
size_t startingNumSnapshots = mSnapshotBuilder.getSnapshots().size();
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/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;
}