summaryrefslogtreecommitdiff
path: root/hwc2/common/observers/SoftVsyncObserver.cpp (plain)
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
23extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
24 const struct timespec *request,
25 struct timespec *remain);
26
27
28namespace android {
29namespace amlogic {
30
31SoftVsyncObserver::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
43SoftVsyncObserver::~SoftVsyncObserver()
44{
45 WARN_IF_NOT_DEINIT();
46}
47
48bool 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
67void 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
84void 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
98bool 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
115bool 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