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