1 /* 2 // Copyright(c)2014 IntelCorporation 3 // 4 // LicensedundertheApacheLicense,Version2.0(the"License"); 5 // youmaynotusethisfileexceptincompliancewiththeLicense. 6 // YoumayobtainacopyoftheLicenseat 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software 11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS, 12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. 13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand 14 // limitationsundertheLicense. 15 */ 16 #include <HwcTrace.h> 17 #include <SoftVsyncObserver.h> 18 #include <IDisplayDevice.h> 19 20 extern "C" int clock_nanosleep(clockid_t clock_id, int flags, 21 const struct timespec *request, 22 struct timespec *remain); 23 24 25 namespace android { 26 namespace intel { 27 28 SoftVsyncObserver::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 42 SoftVsyncObserver::~SoftVsyncObserver() 43 { 44 WARN_IF_NOT_DEINIT(); 45 } 46 47 bool SoftVsyncObserver::initialize() 48 { 49 if (mInitialized) { 50 WTRACE("object has been initialized"); 51 return true; 52 } 53 54 mExitThread = false; 55 mEnabled = false; 56 mRefreshRate = 60/mDisplayDevice.getFpsDivider(); 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 67 void SoftVsyncObserver::deinitialize() 68 { 69 if (mEnabled) { 70 WTRACE("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 84 void SoftVsyncObserver::setRefreshRate(int rate) 85 { 86 if (mEnabled) { 87 WTRACE("too late to set refresh rate"); 88 } else if (rate < 1 || rate > 120) { 89 WTRACE("invalid refresh rate %d", rate); 90 } else { 91 mRefreshRate = rate; 92 } 93 } 94 95 bool SoftVsyncObserver::control(bool enabled) 96 { 97 if (enabled == mEnabled) { 98 WTRACE("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 111 bool SoftVsyncObserver::threadLoop() 112 { 113 { // scope for lock 114 Mutex::Autolock _l(mLock); 115 while (!mEnabled) { 116 mCondition.wait(mLock); 117 if (mExitThread) { 118 ITRACE("exiting thread loop"); 119 return false; 120 } 121 } 122 } 123 124 125 const nsecs_t period = mRefreshPeriod * mDisplayDevice.getFpsDivider(); 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