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(×tamp);
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