xref: /aosp_15_r20/external/drm_hwcomposer/drm/VSyncWorker.cpp (revision 0a9764fe0a15e71ebbeb85e87e10990c23aab47f)
1*0a9764feSAndroid Build Coastguard Worker /*
2*0a9764feSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*0a9764feSAndroid Build Coastguard Worker  *
4*0a9764feSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*0a9764feSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*0a9764feSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*0a9764feSAndroid Build Coastguard Worker  *
8*0a9764feSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*0a9764feSAndroid Build Coastguard Worker  *
10*0a9764feSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*0a9764feSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*0a9764feSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0a9764feSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*0a9764feSAndroid Build Coastguard Worker  * limitations under the License.
15*0a9764feSAndroid Build Coastguard Worker  */
16*0a9764feSAndroid Build Coastguard Worker 
17*0a9764feSAndroid Build Coastguard Worker #define LOG_TAG "drmhwc"
18*0a9764feSAndroid Build Coastguard Worker 
19*0a9764feSAndroid Build Coastguard Worker #include "VSyncWorker.h"
20*0a9764feSAndroid Build Coastguard Worker 
21*0a9764feSAndroid Build Coastguard Worker #include <xf86drm.h>
22*0a9764feSAndroid Build Coastguard Worker #include <xf86drmMode.h>
23*0a9764feSAndroid Build Coastguard Worker 
24*0a9764feSAndroid Build Coastguard Worker #include <cstdlib>
25*0a9764feSAndroid Build Coastguard Worker #include <cstring>
26*0a9764feSAndroid Build Coastguard Worker #include <ctime>
27*0a9764feSAndroid Build Coastguard Worker 
28*0a9764feSAndroid Build Coastguard Worker #include "drm/ResourceManager.h"
29*0a9764feSAndroid Build Coastguard Worker #include "utils/log.h"
30*0a9764feSAndroid Build Coastguard Worker 
31*0a9764feSAndroid Build Coastguard Worker namespace android {
32*0a9764feSAndroid Build Coastguard Worker 
CreateInstance(std::shared_ptr<DrmDisplayPipeline> & pipe,VSyncWorkerCallbacks & callbacks)33*0a9764feSAndroid Build Coastguard Worker auto VSyncWorker::CreateInstance(std::shared_ptr<DrmDisplayPipeline> &pipe,
34*0a9764feSAndroid Build Coastguard Worker                                  VSyncWorkerCallbacks &callbacks)
35*0a9764feSAndroid Build Coastguard Worker     -> std::shared_ptr<VSyncWorker> {
36*0a9764feSAndroid Build Coastguard Worker   auto vsw = std::shared_ptr<VSyncWorker>(new VSyncWorker());
37*0a9764feSAndroid Build Coastguard Worker 
38*0a9764feSAndroid Build Coastguard Worker   vsw->callbacks_ = callbacks;
39*0a9764feSAndroid Build Coastguard Worker 
40*0a9764feSAndroid Build Coastguard Worker   if (pipe) {
41*0a9764feSAndroid Build Coastguard Worker     vsw->high_crtc_ = pipe->crtc->Get()->GetIndexInResArray()
42*0a9764feSAndroid Build Coastguard Worker                       << DRM_VBLANK_HIGH_CRTC_SHIFT;
43*0a9764feSAndroid Build Coastguard Worker     vsw->drm_fd_ = pipe->device->GetFd();
44*0a9764feSAndroid Build Coastguard Worker   }
45*0a9764feSAndroid Build Coastguard Worker 
46*0a9764feSAndroid Build Coastguard Worker   std::thread(&VSyncWorker::ThreadFn, vsw.get(), vsw).detach();
47*0a9764feSAndroid Build Coastguard Worker 
48*0a9764feSAndroid Build Coastguard Worker   return vsw;
49*0a9764feSAndroid Build Coastguard Worker }
50*0a9764feSAndroid Build Coastguard Worker 
VSyncControl(bool enabled)51*0a9764feSAndroid Build Coastguard Worker void VSyncWorker::VSyncControl(bool enabled) {
52*0a9764feSAndroid Build Coastguard Worker   {
53*0a9764feSAndroid Build Coastguard Worker     const std::lock_guard<std::mutex> lock(mutex_);
54*0a9764feSAndroid Build Coastguard Worker     enabled_ = enabled;
55*0a9764feSAndroid Build Coastguard Worker     last_timestamp_ = -1;
56*0a9764feSAndroid Build Coastguard Worker   }
57*0a9764feSAndroid Build Coastguard Worker 
58*0a9764feSAndroid Build Coastguard Worker   cv_.notify_all();
59*0a9764feSAndroid Build Coastguard Worker }
60*0a9764feSAndroid Build Coastguard Worker 
StopThread()61*0a9764feSAndroid Build Coastguard Worker void VSyncWorker::StopThread() {
62*0a9764feSAndroid Build Coastguard Worker   {
63*0a9764feSAndroid Build Coastguard Worker     const std::lock_guard<std::mutex> lock(mutex_);
64*0a9764feSAndroid Build Coastguard Worker     thread_exit_ = true;
65*0a9764feSAndroid Build Coastguard Worker     enabled_ = false;
66*0a9764feSAndroid Build Coastguard Worker     callbacks_ = {};
67*0a9764feSAndroid Build Coastguard Worker   }
68*0a9764feSAndroid Build Coastguard Worker 
69*0a9764feSAndroid Build Coastguard Worker   cv_.notify_all();
70*0a9764feSAndroid Build Coastguard Worker }
71*0a9764feSAndroid Build Coastguard Worker 
72*0a9764feSAndroid Build Coastguard Worker /*
73*0a9764feSAndroid Build Coastguard Worker  * Returns the timestamp of the next vsync in phase with last_timestamp_.
74*0a9764feSAndroid Build Coastguard Worker  * For example:
75*0a9764feSAndroid Build Coastguard Worker  *  last_timestamp_ = 137
76*0a9764feSAndroid Build Coastguard Worker  *  frame_ns = 50
77*0a9764feSAndroid Build Coastguard Worker  *  current = 683
78*0a9764feSAndroid Build Coastguard Worker  *
79*0a9764feSAndroid Build Coastguard Worker  *  ret = (50 * ((683 - 137)/50 + 1)) + 137
80*0a9764feSAndroid Build Coastguard Worker  *  ret = 687
81*0a9764feSAndroid Build Coastguard Worker  *
82*0a9764feSAndroid Build Coastguard Worker  *  Thus, we must sleep until timestamp 687 to maintain phase with the last
83*0a9764feSAndroid Build Coastguard Worker  *  timestamp.
84*0a9764feSAndroid Build Coastguard Worker  */
GetPhasedVSync(int64_t frame_ns,int64_t current) const85*0a9764feSAndroid Build Coastguard Worker int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) const {
86*0a9764feSAndroid Build Coastguard Worker   if (last_timestamp_ < 0)
87*0a9764feSAndroid Build Coastguard Worker     return current + frame_ns;
88*0a9764feSAndroid Build Coastguard Worker 
89*0a9764feSAndroid Build Coastguard Worker   return frame_ns * ((current - last_timestamp_) / frame_ns + 1) +
90*0a9764feSAndroid Build Coastguard Worker          last_timestamp_;
91*0a9764feSAndroid Build Coastguard Worker }
92*0a9764feSAndroid Build Coastguard Worker 
93*0a9764feSAndroid Build Coastguard Worker static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
94*0a9764feSAndroid Build Coastguard Worker 
SyntheticWaitVBlank(int64_t * timestamp)95*0a9764feSAndroid Build Coastguard Worker int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
96*0a9764feSAndroid Build Coastguard Worker   auto time_now = ResourceManager::GetTimeMonotonicNs();
97*0a9764feSAndroid Build Coastguard Worker 
98*0a9764feSAndroid Build Coastguard Worker   // Default to 60Hz refresh rate
99*0a9764feSAndroid Build Coastguard Worker   constexpr uint32_t kDefaultVSPeriodNs = 16666666;
100*0a9764feSAndroid Build Coastguard Worker   auto period_ns = kDefaultVSPeriodNs;
101*0a9764feSAndroid Build Coastguard Worker   if (callbacks_.get_vperiod_ns && callbacks_.get_vperiod_ns() != 0)
102*0a9764feSAndroid Build Coastguard Worker     period_ns = callbacks_.get_vperiod_ns();
103*0a9764feSAndroid Build Coastguard Worker 
104*0a9764feSAndroid Build Coastguard Worker   auto phased_timestamp = GetPhasedVSync(period_ns, time_now);
105*0a9764feSAndroid Build Coastguard Worker   struct timespec vsync {};
106*0a9764feSAndroid Build Coastguard Worker   vsync.tv_sec = int(phased_timestamp / kOneSecondNs);
107*0a9764feSAndroid Build Coastguard Worker   vsync.tv_nsec = int(phased_timestamp - (vsync.tv_sec * kOneSecondNs));
108*0a9764feSAndroid Build Coastguard Worker 
109*0a9764feSAndroid Build Coastguard Worker   int ret = 0;
110*0a9764feSAndroid Build Coastguard Worker   do {
111*0a9764feSAndroid Build Coastguard Worker     ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, nullptr);
112*0a9764feSAndroid Build Coastguard Worker   } while (ret == EINTR);
113*0a9764feSAndroid Build Coastguard Worker   if (ret != 0)
114*0a9764feSAndroid Build Coastguard Worker     return ret;
115*0a9764feSAndroid Build Coastguard Worker 
116*0a9764feSAndroid Build Coastguard Worker   *timestamp = phased_timestamp;
117*0a9764feSAndroid Build Coastguard Worker   return 0;
118*0a9764feSAndroid Build Coastguard Worker }
119*0a9764feSAndroid Build Coastguard Worker 
ThreadFn(const std::shared_ptr<VSyncWorker> & vsw)120*0a9764feSAndroid Build Coastguard Worker void VSyncWorker::ThreadFn(const std::shared_ptr<VSyncWorker> &vsw) {
121*0a9764feSAndroid Build Coastguard Worker   int ret = 0;
122*0a9764feSAndroid Build Coastguard Worker 
123*0a9764feSAndroid Build Coastguard Worker   for (;;) {
124*0a9764feSAndroid Build Coastguard Worker     {
125*0a9764feSAndroid Build Coastguard Worker       std::unique_lock<std::mutex> lock(vsw->mutex_);
126*0a9764feSAndroid Build Coastguard Worker       if (thread_exit_)
127*0a9764feSAndroid Build Coastguard Worker         break;
128*0a9764feSAndroid Build Coastguard Worker 
129*0a9764feSAndroid Build Coastguard Worker       if (!enabled_)
130*0a9764feSAndroid Build Coastguard Worker         vsw->cv_.wait(lock);
131*0a9764feSAndroid Build Coastguard Worker 
132*0a9764feSAndroid Build Coastguard Worker       if (!enabled_)
133*0a9764feSAndroid Build Coastguard Worker         continue;
134*0a9764feSAndroid Build Coastguard Worker     }
135*0a9764feSAndroid Build Coastguard Worker 
136*0a9764feSAndroid Build Coastguard Worker     ret = -EAGAIN;
137*0a9764feSAndroid Build Coastguard Worker     int64_t timestamp = 0;
138*0a9764feSAndroid Build Coastguard Worker     drmVBlank vblank{};
139*0a9764feSAndroid Build Coastguard Worker 
140*0a9764feSAndroid Build Coastguard Worker     if (drm_fd_) {
141*0a9764feSAndroid Build Coastguard Worker       vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
142*0a9764feSAndroid Build Coastguard Worker                                                (high_crtc_ &
143*0a9764feSAndroid Build Coastguard Worker                                                 DRM_VBLANK_HIGH_CRTC_MASK));
144*0a9764feSAndroid Build Coastguard Worker       vblank.request.sequence = 1;
145*0a9764feSAndroid Build Coastguard Worker 
146*0a9764feSAndroid Build Coastguard Worker       ret = drmWaitVBlank(*drm_fd_, &vblank);
147*0a9764feSAndroid Build Coastguard Worker       if (ret == -EINTR)
148*0a9764feSAndroid Build Coastguard Worker         continue;
149*0a9764feSAndroid Build Coastguard Worker     }
150*0a9764feSAndroid Build Coastguard Worker 
151*0a9764feSAndroid Build Coastguard Worker     if (ret != 0) {
152*0a9764feSAndroid Build Coastguard Worker       ret = SyntheticWaitVBlank(&timestamp);
153*0a9764feSAndroid Build Coastguard Worker       if (ret != 0)
154*0a9764feSAndroid Build Coastguard Worker         continue;
155*0a9764feSAndroid Build Coastguard Worker     } else {
156*0a9764feSAndroid Build Coastguard Worker       constexpr int kUsToNsMul = 1000;
157*0a9764feSAndroid Build Coastguard Worker       timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
158*0a9764feSAndroid Build Coastguard Worker                   (int64_t)vblank.reply.tval_usec * kUsToNsMul;
159*0a9764feSAndroid Build Coastguard Worker     }
160*0a9764feSAndroid Build Coastguard Worker 
161*0a9764feSAndroid Build Coastguard Worker     decltype(callbacks_.out_event) callback;
162*0a9764feSAndroid Build Coastguard Worker 
163*0a9764feSAndroid Build Coastguard Worker     {
164*0a9764feSAndroid Build Coastguard Worker       const std::lock_guard<std::mutex> lock(mutex_);
165*0a9764feSAndroid Build Coastguard Worker       if (!enabled_)
166*0a9764feSAndroid Build Coastguard Worker         continue;
167*0a9764feSAndroid Build Coastguard Worker       callback = callbacks_.out_event;
168*0a9764feSAndroid Build Coastguard Worker     }
169*0a9764feSAndroid Build Coastguard Worker 
170*0a9764feSAndroid Build Coastguard Worker     if (callback)
171*0a9764feSAndroid Build Coastguard Worker       callback(timestamp);
172*0a9764feSAndroid Build Coastguard Worker 
173*0a9764feSAndroid Build Coastguard Worker     last_timestamp_ = timestamp;
174*0a9764feSAndroid Build Coastguard Worker   }
175*0a9764feSAndroid Build Coastguard Worker 
176*0a9764feSAndroid Build Coastguard Worker   ALOGI("VSyncWorker thread exit");
177*0a9764feSAndroid Build Coastguard Worker }
178*0a9764feSAndroid Build Coastguard Worker }  // namespace android
179