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
17#include <HwcTrace.h>
18#include <IDisplayDevice.h>
19#include <DisplayQuery.h>
20#include <BufferManager.h>
21#include <DisplayPlaneManager.h>
22#include <Hwcomposer.h>
23#include <VsyncManager.h>
24
25
26namespace android {
27namespace intel {
28
29VsyncManager::VsyncManager(Hwcomposer &hwc)
30     :mHwc(hwc),
31      mInitialized(false),
32      mEnableDynamicVsync(true),
33      mEnabled(false),
34      mVsyncSource(IDisplayDevice::DEVICE_COUNT),
35      mLock()
36{
37}
38
39VsyncManager::~VsyncManager()
40{
41    WARN_IF_NOT_DEINIT();
42}
43
44bool VsyncManager::initialize()
45{
46
47    mEnabled = false;
48    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
49    mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
50    mInitialized = true;
51    return true;
52}
53
54void VsyncManager::deinitialize()
55{
56    if (mEnabled) {
57        WTRACE("vsync is still enabled");
58    }
59
60    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
61    mEnabled = false;
62    mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
63    mInitialized = false;
64}
65
66bool VsyncManager::handleVsyncControl(int disp, bool enabled)
67{
68    Mutex::Autolock l(mLock);
69
70    if (disp != IDisplayDevice::DEVICE_PRIMARY) {
71        WTRACE("vsync control on non-primary device %d", disp);
72        return false;
73    }
74
75    if (mEnabled == enabled) {
76        WTRACE("vsync state %d is not changed", enabled);
77        return true;
78    }
79
80    if (!enabled) {
81        disableVsync();
82        mEnabled = false;
83        return true;
84    } else {
85        mEnabled = enableVsync(getCandidate());
86        return mEnabled;
87    }
88
89    return false;
90}
91
92void VsyncManager::resetVsyncSource()
93{
94    Mutex::Autolock l(mLock);
95
96    if (!mEnableDynamicVsync) {
97        ITRACE("dynamic vsync source switch is not supported");
98        return;
99    }
100
101    if (!mEnabled) {
102        return;
103    }
104
105    int vsyncSource = getCandidate();
106    if (vsyncSource == mVsyncSource) {
107        return;
108    }
109
110    disableVsync();
111    enableVsync(vsyncSource);
112}
113
114int VsyncManager::getVsyncSource()
115{
116    return mVsyncSource;
117}
118
119void VsyncManager::enableDynamicVsync(bool enable)
120{
121    Mutex::Autolock l(mLock);
122    if (scUsePrimaryVsyncOnly) {
123        WTRACE("dynamic vsync is not supported");
124        return;
125    }
126
127    mEnableDynamicVsync = enable;
128
129    if (!mEnabled) {
130        return;
131    }
132
133    int vsyncSource = getCandidate();
134    if (vsyncSource == mVsyncSource) {
135        return;
136    }
137
138    disableVsync();
139    enableVsync(vsyncSource);
140}
141
142IDisplayDevice* VsyncManager::getDisplayDevice(int dispType ) {
143    return mHwc.getDisplayDevice(dispType);
144}
145
146int VsyncManager::getCandidate()
147{
148    if (!mEnableDynamicVsync) {
149        return IDisplayDevice::DEVICE_PRIMARY;
150    }
151
152    IDisplayDevice *device = NULL;
153    // use HDMI vsync when connected
154    device = getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
155    if (device && device->isConnected()) {
156        return IDisplayDevice::DEVICE_EXTERNAL;
157    }
158
159    // use vsync from virtual display when video extended mode is entered
160    if (Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeActive()) {
161        device = getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL);
162        if (device && device->isConnected()) {
163            return IDisplayDevice::DEVICE_VIRTUAL;
164        }
165        WTRACE("Could not use vsync from secondary device");
166    }
167    return IDisplayDevice::DEVICE_PRIMARY;
168}
169
170bool VsyncManager::enableVsync(int candidate)
171{
172    if (mVsyncSource != IDisplayDevice::DEVICE_COUNT) {
173        WTRACE("vsync has been enabled on %d", mVsyncSource);
174        return true;
175    }
176
177    IDisplayDevice *device = getDisplayDevice(candidate);
178    if (!device) {
179        ETRACE("invalid vsync source candidate %d", candidate);
180        return false;
181    }
182
183    if (device->vsyncControl(true)) {
184        mVsyncSource = candidate;
185        return true;
186    }
187
188    if (candidate != IDisplayDevice::DEVICE_PRIMARY) {
189        WTRACE("failed to enable vsync on display %d, fall back to primary", candidate);
190        device = getDisplayDevice(IDisplayDevice::DEVICE_PRIMARY);
191        if (device && device->vsyncControl(true)) {
192            mVsyncSource = IDisplayDevice::DEVICE_PRIMARY;
193            return true;
194        }
195    }
196    ETRACE("failed to enable vsync on the primary display");
197    return false;
198}
199
200void VsyncManager::disableVsync()
201{
202    if (mVsyncSource == IDisplayDevice::DEVICE_COUNT) {
203        WTRACE("vsync has been disabled");
204        return;
205    }
206
207    IDisplayDevice *device = getDisplayDevice(mVsyncSource);
208    if (device && !device->vsyncControl(false)) {
209        WTRACE("failed to disable vsync on device %d", mVsyncSource);
210    }
211    mVsyncSource = IDisplayDevice::DEVICE_COUNT;
212}
213
214} // namespace intel
215} // namespace android
216
217