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
20namespace android {
21namespace intel {
22
23VsyncEventObserver::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
37VsyncEventObserver::~VsyncEventObserver()
38{
39    WARN_IF_NOT_DEINIT();
40}
41
42bool 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
68void 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
87bool 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
107bool 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