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