SF: allow more than one client to use eEarly[Start|End] flags
Bug: 191969790
Test: SF unit tests
Change-Id: I0a21600eba986857e0231e02cb4d59fb108e9bd3
Merged-In: I0a21600eba986857e0231e02cb4d59fb108e9bd3
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 194d808..245db0f 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -46,27 +46,36 @@
return updateVsyncConfigLocked();
}
-VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(
- TransactionSchedule schedule) {
+VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule,
+ const sp<IBinder>& token) {
+ std::lock_guard<std::mutex> lock(mMutex);
switch (schedule) {
case Schedule::EarlyStart:
- ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
- mEarlyWakeup = true;
+ if (token) {
+ mEarlyWakeupRequests.emplace(token);
+ token->linkToDeath(this);
+ } else {
+ ALOGW("%s: EarlyStart requested without a valid token", __func__);
+ }
break;
- case Schedule::EarlyEnd:
- ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
- mEarlyWakeup = false;
+ case Schedule::EarlyEnd: {
+ if (token && mEarlyWakeupRequests.erase(token) > 0) {
+ token->unlinkToDeath(this);
+ } else {
+ ALOGW("%s: Unexpected EarlyEnd", __func__);
+ }
break;
+ }
case Schedule::Late:
// No change to mEarlyWakeup for non-explicit states.
break;
}
if (mTraceDetailedInfo) {
- ATRACE_INT("mEarlyWakeup", mEarlyWakeup);
+ ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size()));
}
- if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) {
+ if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) {
mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
mEarlyTransactionStartTime = mNow();
}
@@ -76,7 +85,7 @@
return std::nullopt;
}
mTransactionSchedule = schedule;
- return updateVsyncConfig();
+ return updateVsyncConfigLocked();
}
VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() {
@@ -128,8 +137,8 @@
const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
- if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 ||
- mRefreshRateChangePending) {
+ if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
+ mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
return mVsyncConfigSet.early;
} else if (mEarlyGpuFrames > 0) {
return mVsyncConfigSet.earlyGpu;
@@ -160,4 +169,11 @@
return offsets;
}
+void VsyncModulator::binderDied(const wp<IBinder>& who) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mEarlyWakeupRequests.erase(who);
+
+ static_cast<void>(updateVsyncConfigLocked());
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 9410768..b2b0451 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -19,8 +19,10 @@
#include <chrono>
#include <mutex>
#include <optional>
+#include <unordered_set>
#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
#include <utils/Timers.h>
namespace android::scheduler {
@@ -35,7 +37,7 @@
};
// Modulates VSYNC phase depending on transaction schedule and refresh rate changes.
-class VsyncModulator {
+class VsyncModulator : public IBinder::DeathRecipient {
public:
// Number of frames to keep early offsets after an early transaction or GPU composition.
// This acts as a low-pass filter in case subsequent transactions are delayed, or if the
@@ -91,7 +93,8 @@
[[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
// Changes offsets in response to transaction flags or commit.
- [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule);
+ [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule,
+ const sp<IBinder>& = {}) EXCLUDES(mMutex);
[[nodiscard]] VsyncConfigOpt onTransactionCommit();
// Called when we send a refresh rate change to hardware composer, so that
@@ -104,6 +107,10 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
+protected:
+ // Called from unit tests as well
+ void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
+
private:
const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
@@ -116,8 +123,14 @@
using Schedule = TransactionSchedule;
std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
- std::atomic<bool> mEarlyWakeup = false;
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex);
std::atomic<bool> mRefreshRateChangePending = false;
std::atomic<int> mEarlyTransactionFrames = 0;