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