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