1 /*
2  * Copyright (C) 2015 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 
17 #define LOG_TAG "hwc-vsync-worker"
18 
19 #include "VSyncWorker.h"
20 
21 #include <log/log.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include <xf86drm.h>
25 #include <xf86drmMode.h>
26 
27 namespace android {
28 
VSyncWorker()29 VSyncWorker::VSyncWorker()
30     : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY),
31       drm_(NULL),
32       display_(-1),
33       enabled_(false),
34       last_timestamp_(-1) {
35 }
36 
~VSyncWorker()37 VSyncWorker::~VSyncWorker() {
38 }
39 
Init(DrmDevice * drm,int display)40 int VSyncWorker::Init(DrmDevice *drm, int display) {
41   drm_ = drm;
42   display_ = display;
43 
44   return InitWorker();
45 }
46 
RegisterCallback(std::shared_ptr<VsyncCallback> callback)47 void VSyncWorker::RegisterCallback(std::shared_ptr<VsyncCallback> callback) {
48   Lock();
49   callback_ = callback;
50   Unlock();
51 }
52 
RegisterClientCallback(hwc2_callback_data_t data,hwc2_function_pointer_t hook)53 void VSyncWorker::RegisterClientCallback(hwc2_callback_data_t data,
54                                          hwc2_function_pointer_t hook) {
55   Lock();
56   vsync_callback_data_ = data;
57   vsync_callback_hook_ = reinterpret_cast<HWC2_PFN_VSYNC>(hook);
58   Unlock();
59 }
60 
VSyncControl(bool enabled)61 void VSyncWorker::VSyncControl(bool enabled) {
62   Lock();
63   enabled_ = enabled;
64   last_timestamp_ = -1;
65   Unlock();
66 
67   Signal();
68 }
69 
70 /*
71  * Returns the timestamp of the next vsync in phase with last_timestamp_.
72  * For example:
73  *  last_timestamp_ = 137
74  *  frame_ns = 50
75  *  current = 683
76  *
77  *  ret = (50 * ((683 - 137)/50 + 1)) + 137
78  *  ret = 687
79  *
80  *  Thus, we must sleep until timestamp 687 to maintain phase with the last
81  *  timestamp.
82  */
GetPhasedVSync(int64_t frame_ns,int64_t current)83 int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) {
84   if (last_timestamp_ < 0)
85     return current + frame_ns;
86 
87   return frame_ns * ((current - last_timestamp_) / frame_ns + 1) +
88          last_timestamp_;
89 }
90 
91 static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
92 
SyntheticWaitVBlank(int64_t * timestamp)93 int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
94   struct timespec vsync;
95   int ret = clock_gettime(CLOCK_MONOTONIC, &vsync);
96 
97   float refresh = 60.0f;  // Default to 60Hz refresh rate
98   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
99   if (conn && conn->active_mode().v_refresh() != 0.0f)
100     refresh = conn->active_mode().v_refresh();
101   else
102     ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn,
103           conn ? conn->active_mode().v_refresh() : 0.0f);
104 
105   int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh,
106                                             vsync.tv_sec * kOneSecondNs +
107                                                 vsync.tv_nsec);
108   vsync.tv_sec = phased_timestamp / kOneSecondNs;
109   vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs);
110   do {
111     ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL);
112   } while (ret == -1 && errno == EINTR);
113   if (ret)
114     return ret;
115 
116   *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec;
117   return 0;
118 }
119 
Routine()120 void VSyncWorker::Routine() {
121   int ret;
122 
123   Lock();
124   if (!enabled_) {
125     ret = WaitForSignalOrExitLocked();
126     if (ret == -EINTR) {
127       Unlock();
128       return;
129     }
130   }
131 
132   int display = display_;
133   std::shared_ptr<VsyncCallback> callback(callback_);
134   Unlock();
135 
136   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
137   if (!crtc) {
138     ALOGE("Failed to get crtc for display");
139     return;
140   }
141   uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
142 
143   drmVBlank vblank;
144   memset(&vblank, 0, sizeof(vblank));
145   vblank.request.type = (drmVBlankSeqType)(
146       DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
147   vblank.request.sequence = 1;
148 
149   int64_t timestamp;
150   ret = drmWaitVBlank(drm_->fd(), &vblank);
151   if (ret == -EINTR) {
152     return;
153   } else if (ret) {
154     ret = SyntheticWaitVBlank(&timestamp);
155     if (ret)
156       return;
157   } else {
158     timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
159                 (int64_t)vblank.reply.tval_usec * 1000;
160   }
161 
162   if (!enabled_)
163     return;
164 
165   if (callback)
166     callback->Callback(display, timestamp);
167 
168   Lock();
169   if (enabled_ && vsync_callback_hook_ && vsync_callback_data_)
170     vsync_callback_hook_(vsync_callback_data_, display, timestamp);
171   Unlock();
172 
173   last_timestamp_ = timestamp;
174 }
175 }  // namespace android
176