Home | History | Annotate | Download | only in observers
      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 <common/utils/HwcTrace.h>
     17 #include <common/observers/SoftVsyncObserver.h>
     18 #include <IDisplayDevice.h>
     19 #include <time.h>
     20 
     21 namespace android {
     22 namespace intel {
     23 
     24 SoftVsyncObserver::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 
     38 SoftVsyncObserver::~SoftVsyncObserver()
     39 {
     40     WARN_IF_NOT_DEINIT();
     41 }
     42 
     43 bool 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 
     63 void 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 
     80 void 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 
     91 bool 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 
    107 bool 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