blob: f739addc969438721c97f82f11b0686a21f6fd6a
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 | // This file is modified by Amlogic, Inc. 2017.01.17. |
17 | */ |
18 | |
19 | #include <HwcTrace.h> |
20 | #include <SoftVsyncObserver.h> |
21 | #include <IDisplayDevice.h> |
22 | |
23 | extern "C" int clock_nanosleep(clockid_t clock_id, int flags, |
24 | const struct timespec *request, |
25 | struct timespec *remain); |
26 | |
27 | |
28 | namespace android { |
29 | namespace amlogic { |
30 | |
31 | SoftVsyncObserver::SoftVsyncObserver(IDisplayDevice& disp) |
32 | : mDisplayDevice(disp), |
33 | mEnabled(false), |
34 | mRefreshPeriod(0), |
35 | mLock(), |
36 | mCondition(), |
37 | mNextFakeVSync(0), |
38 | mExitThread(false), |
39 | mInitialized(false) |
40 | { |
41 | } |
42 | |
43 | SoftVsyncObserver::~SoftVsyncObserver() |
44 | { |
45 | WARN_IF_NOT_DEINIT(); |
46 | } |
47 | |
48 | bool SoftVsyncObserver::initialize() |
49 | { |
50 | if (mInitialized) { |
51 | WTRACE("object has been initialized"); |
52 | return true; |
53 | } |
54 | |
55 | mExitThread = false; |
56 | mEnabled = false; |
57 | mRefreshPeriod = nsecs_t(1e9 / 60); |
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::setRefreshPeriod(nsecs_t period) |
85 | { |
86 | Mutex::Autolock _l(mLock); |
87 | |
88 | if (period <= 0) { |
89 | WTRACE("invalid refresh period %lld", period); |
90 | } else if (mRefreshPeriod != period) { |
91 | mRefreshPeriod = period; |
92 | if (mEnabled) { |
93 | mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; |
94 | } |
95 | } |
96 | } |
97 | |
98 | bool SoftVsyncObserver::control(bool enabled) |
99 | { |
100 | Mutex::Autolock _l(mLock); |
101 | |
102 | if (enabled == mEnabled) { |
103 | WTRACE("vsync state %d is not changed", enabled); |
104 | return true; |
105 | } |
106 | |
107 | if (enabled) { |
108 | mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; |
109 | } |
110 | mEnabled = enabled; |
111 | mCondition.signal(); |
112 | return true; |
113 | } |
114 | |
115 | bool SoftVsyncObserver::threadLoop() |
116 | { |
117 | { // scope for lock |
118 | Mutex::Autolock _l(mLock); |
119 | while (!mEnabled) { |
120 | mCondition.wait(mLock); |
121 | if (mExitThread) { |
122 | ITRACE("exiting thread loop"); |
123 | return false; |
124 | } |
125 | } |
126 | } |
127 | |
128 | const nsecs_t period = mRefreshPeriod; |
129 | const nsecs_t now = systemTime(CLOCK_MONOTONIC); |
130 | nsecs_t next_vsync = mNextFakeVSync; |
131 | nsecs_t sleep = next_vsync - now; |
132 | //DTRACE("Softvync (%lld), refresh (%lld)", period, nsecs_t(1e9/period)); |
133 | if (sleep < 0) { |
134 | // we missed, find where the next vsync should be |
135 | sleep = (period - ((now - next_vsync) % period)); |
136 | next_vsync = now + sleep; |
137 | } |
138 | mNextFakeVSync = next_vsync + period; |
139 | |
140 | struct timespec spec; |
141 | spec.tv_sec = next_vsync / 1000000000; |
142 | spec.tv_nsec = next_vsync % 1000000000; |
143 | |
144 | int err; |
145 | do { |
146 | err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); |
147 | } while (err < 0 && errno == EINTR); |
148 | |
149 | |
150 | if (err == 0) { |
151 | mDisplayDevice.onVsync(next_vsync); |
152 | } |
153 | |
154 | return true; |
155 | } |
156 | |
157 | } // namespace amlogic |
158 | } // namesapce android |
159 | |
160 |