blob: 6347b8dcdfd7c4e93fe78ec2dbb9e793d514700e
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 | mRefreshRate(60), // default 60 frames per second |
35 | mRefreshPeriod(0), |
36 | mLock(), |
37 | mCondition(), |
38 | mNextFakeVSync(0), |
39 | mExitThread(false), |
40 | mInitialized(false) |
41 | { |
42 | } |
43 | |
44 | SoftVsyncObserver::~SoftVsyncObserver() |
45 | { |
46 | WARN_IF_NOT_DEINIT(); |
47 | } |
48 | |
49 | bool SoftVsyncObserver::initialize() |
50 | { |
51 | if (mInitialized) { |
52 | WTRACE("object has been initialized"); |
53 | return true; |
54 | } |
55 | |
56 | mExitThread = false; |
57 | mEnabled = false; |
58 | mRefreshRate = 60; |
59 | mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); |
60 | mThread = new VsyncEventPollThread(this); |
61 | if (!mThread.get()) { |
62 | DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread."); |
63 | } |
64 | mThread->run("SoftVsyncObserver", PRIORITY_URGENT_DISPLAY); |
65 | mInitialized = true; |
66 | return true; |
67 | } |
68 | |
69 | void SoftVsyncObserver::deinitialize() |
70 | { |
71 | if (mEnabled) { |
72 | WTRACE("soft vsync is still enabled"); |
73 | control(false); |
74 | } |
75 | |
76 | mExitThread = true; |
77 | mCondition.signal(); |
78 | |
79 | if (mThread.get()) { |
80 | mThread->requestExitAndWait(); |
81 | mThread = NULL; |
82 | } |
83 | mInitialized = false; |
84 | } |
85 | |
86 | void SoftVsyncObserver::setRefreshRate(int rate) |
87 | { |
88 | Mutex::Autolock _l(mLock); |
89 | |
90 | if (rate < 1 || rate > 120) { |
91 | WTRACE("invalid refresh rate %d", rate); |
92 | } else if (mRefreshRate != rate) { |
93 | mRefreshRate = rate; |
94 | if (mEnabled) { |
95 | mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); |
96 | mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; |
97 | } |
98 | } |
99 | } |
100 | |
101 | bool SoftVsyncObserver::control(bool enabled) |
102 | { |
103 | Mutex::Autolock _l(mLock); |
104 | |
105 | if (enabled == mEnabled) { |
106 | WTRACE("vsync state %d is not changed", enabled); |
107 | return true; |
108 | } |
109 | |
110 | if (enabled) { |
111 | mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); |
112 | mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; |
113 | } |
114 | mEnabled = enabled; |
115 | mCondition.signal(); |
116 | return true; |
117 | } |
118 | |
119 | bool SoftVsyncObserver::threadLoop() |
120 | { |
121 | { // scope for lock |
122 | Mutex::Autolock _l(mLock); |
123 | while (!mEnabled) { |
124 | mCondition.wait(mLock); |
125 | if (mExitThread) { |
126 | ITRACE("exiting thread loop"); |
127 | return false; |
128 | } |
129 | } |
130 | } |
131 | |
132 | |
133 | const nsecs_t period = mRefreshPeriod; |
134 | const nsecs_t now = systemTime(CLOCK_MONOTONIC); |
135 | nsecs_t next_vsync = mNextFakeVSync; |
136 | nsecs_t sleep = next_vsync - now; |
137 | if (sleep < 0) { |
138 | // we missed, find where the next vsync should be |
139 | sleep = (period - ((now - next_vsync) % period)); |
140 | next_vsync = now + sleep; |
141 | } |
142 | mNextFakeVSync = next_vsync + period; |
143 | |
144 | struct timespec spec; |
145 | spec.tv_sec = next_vsync / 1000000000; |
146 | spec.tv_nsec = next_vsync % 1000000000; |
147 | |
148 | int err; |
149 | do { |
150 | err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); |
151 | } while (err < 0 && errno == EINTR); |
152 | |
153 | |
154 | if (err == 0) { |
155 | mDisplayDevice.onVsync(next_vsync); |
156 | } |
157 | |
158 | return true; |
159 | } |
160 | |
161 | } // namespace amlogic |
162 | } // namesapce android |
163 | |
164 |