• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 namespace android {
22 namespace intel {
23 
SoftVsyncObserver(IDisplayDevice & disp)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 
~SoftVsyncObserver()38 SoftVsyncObserver::~SoftVsyncObserver()
39 {
40     WARN_IF_NOT_DEINIT();
41 }
42 
initialize()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 
deinitialize()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 
setRefreshRate(int rate)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 
control(bool enabled)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 
threadLoop()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