/*
// 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