1/* 2// Copyright (c) 2014 Intel Corporation 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#include <common/utils/HwcTrace.h> 17#include <common/observers/SoftVsyncObserver.h> 18#include <IDisplayDevice.h> 19 20extern "C" int clock_nanosleep(clockid_t clock_id, int flags, 21 const struct timespec *request, 22 struct timespec *remain); 23 24 25namespace android { 26namespace intel { 27 28SoftVsyncObserver::SoftVsyncObserver(IDisplayDevice& disp) 29 : mDisplayDevice(disp), 30 mDevice(IDisplayDevice::DEVICE_COUNT), 31 mEnabled(false), 32 mRefreshRate(60), // default 60 frames per second 33 mRefreshPeriod(0), 34 mLock(), 35 mCondition(), 36 mNextFakeVSync(0), 37 mExitThread(false), 38 mInitialized(false) 39{ 40} 41 42SoftVsyncObserver::~SoftVsyncObserver() 43{ 44 WARN_IF_NOT_DEINIT(); 45} 46 47bool SoftVsyncObserver::initialize() 48{ 49 if (mInitialized) { 50 WLOGTRACE("object has been initialized"); 51 return true; 52 } 53 54 mExitThread = false; 55 mEnabled = false; 56 mRefreshRate = 60; 57 mDevice = mDisplayDevice.getType(); 58 mThread = new VsyncEventPollThread(this); 59 if (!mThread.get()) { 60 DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread."); 61 } 62 mThread->run("SoftVsyncObserver", PRIORITY_URGENT_DISPLAY); 63 mInitialized = true; 64 return true; 65} 66 67void SoftVsyncObserver::deinitialize() 68{ 69 if (mEnabled) { 70 WLOGTRACE("soft vsync is still enabled"); 71 control(false); 72 } 73 74 mExitThread = true; 75 mCondition.signal(); 76 77 if (mThread.get()) { 78 mThread->requestExitAndWait(); 79 mThread = NULL; 80 } 81 mInitialized = false; 82} 83 84void SoftVsyncObserver::setRefreshRate(int rate) 85{ 86 if (mEnabled) { 87 WLOGTRACE("too late to set refresh rate"); 88 } else if (rate < 1 || rate > 120) { 89 WLOGTRACE("invalid refresh rate %d", rate); 90 } else { 91 mRefreshRate = rate; 92 } 93} 94 95bool SoftVsyncObserver::control(bool enabled) 96{ 97 if (enabled == mEnabled) { 98 WLOGTRACE("vsync state %d is not changed", enabled); 99 return true; 100 } 101 102 if (enabled) { 103 mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); 104 mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; 105 } 106 mEnabled = enabled; 107 mCondition.signal(); 108 return true; 109} 110 111bool SoftVsyncObserver::threadLoop() 112{ 113 { // scope for lock 114 Mutex::Autolock _l(mLock); 115 while (!mEnabled) { 116 mCondition.wait(mLock); 117 if (mExitThread) { 118 ILOGTRACE("exiting thread loop"); 119 return false; 120 } 121 } 122 } 123 124 125 const nsecs_t period = mRefreshPeriod; 126 const nsecs_t now = systemTime(CLOCK_MONOTONIC); 127 nsecs_t next_vsync = mNextFakeVSync; 128 nsecs_t sleep = next_vsync - now; 129 if (sleep < 0) { 130 // we missed, find where the next vsync should be 131 sleep = (period - ((now - next_vsync) % period)); 132 next_vsync = now + sleep; 133 } 134 mNextFakeVSync = next_vsync + period; 135 136 struct timespec spec; 137 spec.tv_sec = next_vsync / 1000000000; 138 spec.tv_nsec = next_vsync % 1000000000; 139 140 int err; 141 do { 142 err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); 143 } while (err < 0 && errno == EINTR); 144 145 146 if (err == 0) { 147 mDisplayDevice.onVsync(next_vsync); 148 } 149 150 return true; 151} 152 153} // namespace intel 154} // namesapce android 155 156