summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Scheduler/DispSyncSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/Scheduler/DispSyncSource.cpp')
-rw-r--r--services/surfaceflinger/Scheduler/DispSyncSource.cpp158
1 files changed, 115 insertions, 43 deletions
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 8752b6600e..50b38c9cf6 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "DispSyncSource.h"
@@ -26,37 +22,127 @@
#include <utils/Trace.h>
#include <mutex>
-#include "DispSync.h"
#include "EventThread.h"
+#include "VsyncController.h"
-namespace android {
+namespace android::scheduler {
using base::StringAppendF;
+using namespace std::chrono_literals;
+
+class CallbackRepeater {
+public:
+ CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
+ std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+ std::chrono::nanoseconds notBefore)
+ : mName(name),
+ mCallback(cb),
+ mRegistration(dispatch,
+ std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ mName),
+ mStarted(false),
+ mWorkDuration(workDuration),
+ mReadyDuration(readyDuration),
+ mLastCallTime(notBefore) {}
+
+ ~CallbackRepeater() {
+ std::lock_guard lock(mMutex);
+ mRegistration.cancel();
+ }
+
+ void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
+ std::lock_guard lock(mMutex);
+ mStarted = true;
+ mWorkDuration = workDuration;
+ mReadyDuration = readyDuration;
+
+ auto const scheduleResult =
+ mRegistration.schedule({.workDuration = mWorkDuration.count(),
+ .readyDuration = mReadyDuration.count(),
+ .earliestVsync = mLastCallTime.count()});
+ LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
+ }
+
+ void stop() {
+ std::lock_guard lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
+ mStarted = false;
+ mRegistration.cancel();
+ }
+
+ void dump(std::string& result) const {
+ std::lock_guard lock(mMutex);
+ const auto relativeLastCallTime =
+ mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
+ StringAppendF(&result, "\t%s: ", mName.c_str());
+ StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
+ mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
+ StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
+ mStarted ? "running" : "stopped");
+ }
+
+private:
+ void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
+ {
+ std::lock_guard lock(mMutex);
+ mLastCallTime = std::chrono::nanoseconds(vsyncTime);
+ }
+
+ mCallback(vsyncTime, wakeupTime, readyTime);
+
+ {
+ std::lock_guard lock(mMutex);
+ if (!mStarted) {
+ return;
+ }
+ auto const scheduleResult =
+ mRegistration.schedule({.workDuration = mWorkDuration.count(),
+ .readyDuration = mReadyDuration.count(),
+ .earliestVsync = vsyncTime});
+ LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");
+ }
+ }
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+ const std::string mName;
+ scheduler::VSyncDispatch::Callback mCallback;
+
+ mutable std::mutex mMutex;
+ VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
+ bool mStarted GUARDED_BY(mMutex) = false;
+ std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
+ std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
+ std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
+};
+
+DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration, bool traceVsync,
const char* name)
: mName(name),
mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mDispSync(dispSync),
- mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {}
+ mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
+ mReadyDuration(readyDuration) {
+ mCallbackRepeater =
+ std::make_unique<CallbackRepeater>(vSyncDispatch,
+ std::bind(&DispSyncSource::onVsyncCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2,
+ std::placeholders::_3),
+ name, workDuration, readyDuration,
+ std::chrono::steady_clock::now().time_since_epoch());
+}
+
+DispSyncSource::~DispSyncSource() = default;
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this),
- mLastCallbackTime);
- if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->start(mWorkDuration, mReadyDuration);
// ATRACE_INT(mVsyncOnLabel.c_str(), 1);
} else {
- status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this),
- &mLastCallbackTime);
- if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->stop();
// ATRACE_INT(mVsyncOnLabel.c_str(), 0);
}
mEnabled = enable;
@@ -67,32 +153,22 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
mCallback = callback;
}
-void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
+void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
std::lock_guard lock(mVsyncMutex);
- const nsecs_t period = mDispSync->getPeriod();
-
- // Normalize phaseOffset to [-period, period)
- const int numPeriods = phaseOffset / period;
- phaseOffset -= numPeriods * period;
- if (mPhaseOffset == phaseOffset) {
- return;
- }
-
- mPhaseOffset = phaseOffset;
+ mWorkDuration = workDuration;
+ mReadyDuration = readyDuration;
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
return;
}
- status_t err =
- mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this), mPhaseOffset);
- if (err != NO_ERROR) {
- ALOGE("error changing vsync offset: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->start(mWorkDuration, mReadyDuration);
}
-void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
+void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
+ nsecs_t readyTime) {
VSyncSource::Callback* callback;
{
std::lock_guard lock(mCallbackMutex);
@@ -104,17 +180,13 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestam
}
if (callback != nullptr) {
- callback->onVSyncEvent(when, expectedVSyncTimestamp);
+ callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
}
}
void DispSyncSource::dump(std::string& result) const {
std::lock_guard lock(mVsyncMutex);
StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
- mDispSync->dump(result);
}
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+} // namespace android::scheduler