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 <VsyncEventObserver.h>
18 #include <PhysicalDevice.h>
19
20 namespace android {
21 namespace intel {
22
VsyncEventObserver(PhysicalDevice & disp)23 VsyncEventObserver::VsyncEventObserver(PhysicalDevice& disp)
24 : mLock(),
25 mCondition(),
26 mDisplayDevice(disp),
27 mVsyncControl(NULL),
28 mDevice(IDisplayDevice::DEVICE_COUNT),
29 mEnabled(false),
30 mExitThread(false),
31 mInitialized(false),
32 mFpsCounter(0)
33 {
34 CTRACE();
35 }
36
~VsyncEventObserver()37 VsyncEventObserver::~VsyncEventObserver()
38 {
39 WARN_IF_NOT_DEINIT();
40 }
41
initialize()42 bool VsyncEventObserver::initialize()
43 {
44 if (mInitialized) {
45 WTRACE("object has been initialized");
46 return true;
47 }
48
49 mExitThread = false;
50 mEnabled = false;
51 mDevice = mDisplayDevice.getType();
52 mVsyncControl = mDisplayDevice.createVsyncControl();
53 if (!mVsyncControl || !mVsyncControl->initialize()) {
54 DEINIT_AND_RETURN_FALSE("failed to initialize vsync control");
55 }
56
57 mThread = new VsyncEventPollThread(this);
58 if (!mThread.get()) {
59 DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread.");
60 }
61
62 mThread->run("VsyncEventObserver", PRIORITY_URGENT_DISPLAY);
63
64 mInitialized = true;
65 return true;
66 }
67
deinitialize()68 void VsyncEventObserver::deinitialize()
69 {
70 if (mEnabled) {
71 WTRACE("vsync is still enabled");
72 control(false);
73 }
74 mInitialized = false;
75 mExitThread = true;
76 mEnabled = false;
77 mCondition.signal();
78
79 if (mThread.get()) {
80 mThread->requestExitAndWait();
81 mThread = NULL;
82 }
83
84 DEINIT_AND_DELETE_OBJ(mVsyncControl);
85 }
86
control(bool enabled)87 bool VsyncEventObserver::control(bool enabled)
88 {
89 ATRACE("enabled = %d on device %d", enabled, mDevice);
90 if (enabled == mEnabled) {
91 WTRACE("vsync state %d is not changed", enabled);
92 return true;
93 }
94
95 Mutex::Autolock _l(mLock);
96 bool ret = mVsyncControl->control(mDevice, enabled);
97 if (!ret) {
98 ETRACE("failed to control (%d) vsync on display %d", enabled, mDevice);
99 return false;
100 }
101
102 mEnabled = enabled;
103 mCondition.signal();
104 return true;
105 }
106
threadLoop()107 bool VsyncEventObserver::threadLoop()
108 {
109 do {
110 // scope for lock
111 Mutex::Autolock _l(mLock);
112 while (!mEnabled) {
113 mCondition.wait(mLock);
114 if (mExitThread) {
115 ITRACE("exiting thread loop");
116 return false;
117 }
118 }
119 } while (0);
120
121 if(mEnabled && mDisplayDevice.isConnected()) {
122 int64_t timestamp;
123 bool ret = mVsyncControl->wait(mDevice, timestamp);
124 if (ret == false) {
125 WTRACE("failed to wait for vsync on display %d, vsync enabled %d", mDevice, mEnabled);
126 usleep(16000);
127 return true;
128 }
129
130 // send vsync event notification every hwc.fps_divider
131 if ((mFpsCounter++) % mDisplayDevice.getFpsDivider() == 0)
132 mDisplayDevice.onVsync(timestamp);
133 }
134
135 return true;
136 }
137
138 } // namespace intel
139 } // namesapce android
140