blob: 75f072dcd4180c719741916c265e92a2994ac5be [file] [log] [blame]
Ana Krulec241cf832018-08-10 15:03:23 -07001/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Midas Chienbc5f22f2018-08-16 15:51:19 +080017#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
Ana Krulec241cf832018-08-10 15:03:23 -070019#include "DispSyncSource.h"
20
Ana Krulec072233f2018-08-10 15:03:23 -070021#include <android-base/stringprintf.h>
Ana Krulec241cf832018-08-10 15:03:23 -070022#include <utils/Trace.h>
Ana Krulec072233f2018-08-10 15:03:23 -070023#include <mutex>
Ana Krulec241cf832018-08-10 15:03:23 -070024
25#include "DispSync.h"
26#include "EventThread.h"
27
Ady Abraham9c53ee72020-07-22 21:16:18 -070028namespace android::scheduler {
Ady Abraham5e7371c2020-03-24 14:47:24 -070029using base::StringAppendF;
Ady Abraham9c53ee72020-07-22 21:16:18 -070030using namespace std::chrono_literals;
Ana Krulec241cf832018-08-10 15:03:23 -070031
Ady Abraham9c53ee72020-07-22 21:16:18 -070032// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
33// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
34// for now.
35class CallbackRepeater {
36public:
37 CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
38 std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
39 std::chrono::nanoseconds notBefore)
40 : mName(name),
41 mCallback(cb),
42 mRegistration(dispatch,
43 std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
44 std::placeholders::_2, std::placeholders::_3),
45 mName),
46 mStarted(false),
47 mWorkDuration(workDuration),
48 mReadyDuration(readyDuration),
49 mLastCallTime(notBefore) {}
50
51 ~CallbackRepeater() {
52 std::lock_guard lock(mMutex);
53 mRegistration.cancel();
54 }
55
56 void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
57 std::lock_guard lock(mMutex);
58 mStarted = true;
59 mWorkDuration = workDuration;
60 mReadyDuration = readyDuration;
61
62 auto const scheduleResult =
63 mRegistration.schedule({.workDuration = mWorkDuration.count(),
64 .readyDuration = mReadyDuration.count(),
65 .earliestVsync = mLastCallTime.count()});
66 LOG_ALWAYS_FATAL_IF((scheduleResult != scheduler::ScheduleResult::Scheduled),
67 "Error scheduling callback: rc %X", scheduleResult);
68 }
69
70 void stop() {
71 std::lock_guard lock(mMutex);
72 LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
73 mStarted = false;
74 mRegistration.cancel();
75 }
76
77 void dump(std::string& result) const {
78 std::lock_guard lock(mMutex);
79 const auto relativeLastCallTime =
80 mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
81 StringAppendF(&result, "\t%s: ", mName.c_str());
82 StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
83 mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
84 StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
85 mStarted ? "running" : "stopped");
86 }
87
88private:
89 void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
90 {
91 std::lock_guard lock(mMutex);
92 mLastCallTime = std::chrono::nanoseconds(vsyncTime);
93 }
94
95 mCallback(vsyncTime, wakeupTime, readyTime);
96
97 {
98 std::lock_guard lock(mMutex);
99 if (!mStarted) {
100 return;
101 }
102 auto const scheduleResult =
103 mRegistration.schedule({.workDuration = mWorkDuration.count(),
104 .readyDuration = mReadyDuration.count(),
105 .earliestVsync = vsyncTime});
106 LOG_ALWAYS_FATAL_IF((scheduleResult != ScheduleResult::Scheduled),
107 "Error rescheduling callback: rc %X", scheduleResult);
108 }
109 }
110
111 const std::string mName;
112 scheduler::VSyncDispatch::Callback mCallback;
113
114 mutable std::mutex mMutex;
115 VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
116 bool mStarted GUARDED_BY(mMutex) = false;
117 std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
118 std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
119 std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
120};
121
122DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
123 std::chrono::nanoseconds workDuration,
124 std::chrono::nanoseconds readyDuration, bool traceVsync,
Ana Krulec241cf832018-08-10 15:03:23 -0700125 const char* name)
126 : mName(name),
Ady Abraham50204dd2019-07-19 15:47:11 -0700127 mValue(base::StringPrintf("VSYNC-%s", name), 0),
Ana Krulec241cf832018-08-10 15:03:23 -0700128 mTraceVsync(traceVsync),
Ana Krulec072233f2018-08-10 15:03:23 -0700129 mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
Ady Abraham9c53ee72020-07-22 21:16:18 -0700130 mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
131 mReadyDuration(readyDuration) {
132 mCallbackRepeater =
133 std::make_unique<CallbackRepeater>(vSyncDispatch,
134 std::bind(&DispSyncSource::onVsyncCallback, this,
135 std::placeholders::_1,
136 std::placeholders::_2,
137 std::placeholders::_3),
138 name, workDuration, readyDuration,
139 std::chrono::steady_clock::now().time_since_epoch());
140}
141
142DispSyncSource::~DispSyncSource() = default;
Ana Krulec241cf832018-08-10 15:03:23 -0700143
144void DispSyncSource::setVSyncEnabled(bool enable) {
Ana Krulec072233f2018-08-10 15:03:23 -0700145 std::lock_guard lock(mVsyncMutex);
Ana Krulec241cf832018-08-10 15:03:23 -0700146 if (enable) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700147 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
Ana Krulec072233f2018-08-10 15:03:23 -0700148 // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
Ana Krulec241cf832018-08-10 15:03:23 -0700149 } else {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700150 mCallbackRepeater->stop();
Ana Krulec072233f2018-08-10 15:03:23 -0700151 // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
Ana Krulec241cf832018-08-10 15:03:23 -0700152 }
153 mEnabled = enable;
154}
155
156void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
Ana Krulec072233f2018-08-10 15:03:23 -0700157 std::lock_guard lock(mCallbackMutex);
Ana Krulec241cf832018-08-10 15:03:23 -0700158 mCallback = callback;
159}
160
Ady Abraham9c53ee72020-07-22 21:16:18 -0700161void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
162 std::chrono::nanoseconds readyDuration) {
Ana Krulec072233f2018-08-10 15:03:23 -0700163 std::lock_guard lock(mVsyncMutex);
Ady Abraham9c53ee72020-07-22 21:16:18 -0700164 mWorkDuration = workDuration;
165 mReadyDuration = readyDuration;
Ana Krulec241cf832018-08-10 15:03:23 -0700166
167 // If we're not enabled, we don't need to mess with the listeners
168 if (!mEnabled) {
169 return;
170 }
171
Ady Abraham9c53ee72020-07-22 21:16:18 -0700172 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
Ana Krulec241cf832018-08-10 15:03:23 -0700173}
174
Ady Abraham9c53ee72020-07-22 21:16:18 -0700175void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
176 nsecs_t readyTime) {
Ana Krulec241cf832018-08-10 15:03:23 -0700177 VSyncSource::Callback* callback;
178 {
Ana Krulec072233f2018-08-10 15:03:23 -0700179 std::lock_guard lock(mCallbackMutex);
Ana Krulec241cf832018-08-10 15:03:23 -0700180 callback = mCallback;
Alec Mourid7599d82019-05-22 19:58:00 -0700181 }
Ana Krulec241cf832018-08-10 15:03:23 -0700182
Alec Mourid7599d82019-05-22 19:58:00 -0700183 if (mTraceVsync) {
184 mValue = (mValue + 1) % 2;
Ana Krulec241cf832018-08-10 15:03:23 -0700185 }
186
187 if (callback != nullptr) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700188 callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
Ana Krulec241cf832018-08-10 15:03:23 -0700189 }
190}
191
Ady Abraham5e7371c2020-03-24 14:47:24 -0700192void DispSyncSource::dump(std::string& result) const {
193 std::lock_guard lock(mVsyncMutex);
194 StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
Ady Abraham5e7371c2020-03-24 14:47:24 -0700195}
196
Ady Abraham9c53ee72020-07-22 21:16:18 -0700197} // namespace android::scheduler