/*
// Copyright (c) 2014 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include <HwcTrace.h>
#include <IDisplayDevice.h>
#include <DisplayQuery.h>
#include <BufferManager.h>
#include <DisplayPlaneManager.h>
#include <Hwcomposer.h>
#include <VsyncManager.h>
namespace android {
namespace intel {
VsyncManager::VsyncManager(Hwcomposer &hwc)
:mHwc(hwc),
mInitialized(false),
mEnableDynamicVsync(true),
mEnabled(false),
mVsyncSource(IDisplayDevice::DEVICE_COUNT),
mLock()
{
}
VsyncManager::~VsyncManager()
{
WARN_IF_NOT_DEINIT();
}
bool VsyncManager::initialize()
{
mEnabled = false;
mVsyncSource = IDisplayDevice::DEVICE_COUNT;
mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
mInitialized = true;
return true;
}
void VsyncManager::deinitialize()
{
if (mEnabled) {
WTRACE("vsync is still enabled");
}
mVsyncSource = IDisplayDevice::DEVICE_COUNT;
mEnabled = false;
mEnableDynamicVsync = !scUsePrimaryVsyncOnly;
mInitialized = false;
}
bool VsyncManager::handleVsyncControl(int disp, bool enabled)
{
Mutex::Autolock l(mLock);
if (disp != IDisplayDevice::DEVICE_PRIMARY) {
WTRACE("vsync control on non-primary device %d", disp);
return false;
}
if (mEnabled == enabled) {
WTRACE("vsync state %d is not changed", enabled);
return true;
}
if (!enabled) {
disableVsync();
mEnabled = false;
return true;
} else {
mEnabled = enableVsync(getCandidate());
return mEnabled;
}
return false;
}
void VsyncManager::resetVsyncSource()
{
Mutex::Autolock l(mLock);
if (!mEnableDynamicVsync) {
ITRACE("dynamic vsync source switch is not supported");
return;
}
if (!mEnabled) {
return;
}
int vsyncSource = getCandidate();
if (vsyncSource == mVsyncSource) {
return;
}
disableVsync();
enableVsync(vsyncSource);
}
int VsyncManager::getVsyncSource()
{
return mVsyncSource;
}
void VsyncManager::enableDynamicVsync(bool enable)
{
Mutex::Autolock l(mLock);
if (scUsePrimaryVsyncOnly) {
WTRACE("dynamic vsync is not supported");
return;
}
mEnableDynamicVsync = enable;
if (!mEnabled) {
return;
}
int vsyncSource = getCandidate();
if (vsyncSource == mVsyncSource) {
return;
}
disableVsync();
enableVsync(vsyncSource);
}
IDisplayDevice* VsyncManager::getDisplayDevice(int dispType ) {
return mHwc.getDisplayDevice(dispType);
}
int VsyncManager::getCandidate()
{
if (!mEnableDynamicVsync) {
return IDisplayDevice::DEVICE_PRIMARY;
}
IDisplayDevice *device = NULL;
// use HDMI vsync when connected
device = getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
if (device && device->isConnected()) {
return IDisplayDevice::DEVICE_EXTERNAL;
}
// use vsync from virtual display when video extended mode is entered
if (Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeActive()) {
device = getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL);
if (device && device->isConnected()) {
return IDisplayDevice::DEVICE_VIRTUAL;
}
WTRACE("Could not use vsync from secondary device");
}
return IDisplayDevice::DEVICE_PRIMARY;
}
bool VsyncManager::enableVsync(int candidate)
{
if (mVsyncSource != IDisplayDevice::DEVICE_COUNT) {
WTRACE("vsync has been enabled on %d", mVsyncSource);
return true;
}
IDisplayDevice *device = getDisplayDevice(candidate);
if (!device) {
ETRACE("invalid vsync source candidate %d", candidate);
return false;
}
if (device->vsyncControl(true)) {
mVsyncSource = candidate;
return true;
}
if (candidate != IDisplayDevice::DEVICE_PRIMARY) {
WTRACE("failed to enable vsync on display %d, fall back to primary", candidate);
device = getDisplayDevice(IDisplayDevice::DEVICE_PRIMARY);
if (device && device->vsyncControl(true)) {
mVsyncSource = IDisplayDevice::DEVICE_PRIMARY;
return true;
}
}
ETRACE("failed to enable vsync on the primary display");
return false;
}
void VsyncManager::disableVsync()
{
if (mVsyncSource == IDisplayDevice::DEVICE_COUNT) {
WTRACE("vsync has been disabled");
return;
}
IDisplayDevice *device = getDisplayDevice(mVsyncSource);
if (device && !device->vsyncControl(false)) {
WTRACE("failed to disable vsync on device %d", mVsyncSource);
}
mVsyncSource = IDisplayDevice::DEVICE_COUNT;
}
} // namespace intel
} // namespace android