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 <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
SoftVsyncObserver(IDisplayDevice & disp)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
~SoftVsyncObserver()42 SoftVsyncObserver::~SoftVsyncObserver()
43 {
44 WARN_IF_NOT_DEINIT();
45 }
46
initialize()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;
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
deinitialize()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
setRefreshRate(int rate)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
control(bool enabled)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
threadLoop()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;
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