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 <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