/*
// 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 <VsyncEventObserver.h>
#include <PhysicalDevice.h>
namespace android {
namespace intel {
VsyncEventObserver::VsyncEventObserver(PhysicalDevice& disp)
: mLock(),
mCondition(),
mDisplayDevice(disp),
mVsyncControl(NULL),
mDevice(IDisplayDevice::DEVICE_COUNT),
mEnabled(false),
mExitThread(false),
mInitialized(false),
mFpsCounter(0)
{
CTRACE();
}
VsyncEventObserver::~VsyncEventObserver()
{
WARN_IF_NOT_DEINIT();
}
bool VsyncEventObserver::initialize()
{
if (mInitialized) {
WTRACE("object has been initialized");
return true;
}
mExitThread = false;
mEnabled = false;
mDevice = mDisplayDevice.getType();
mVsyncControl = mDisplayDevice.createVsyncControl();
if (!mVsyncControl || !mVsyncControl->initialize()) {
DEINIT_AND_RETURN_FALSE("failed to initialize vsync control");
}
mThread = new VsyncEventPollThread(this);
if (!mThread.get()) {
DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread.");
}
mThread->run("VsyncEventObserver", PRIORITY_URGENT_DISPLAY);
mInitialized = true;
return true;
}
void VsyncEventObserver::deinitialize()
{
if (mEnabled) {
WTRACE("vsync is still enabled");
control(false);
}
mInitialized = false;
mExitThread = true;
mEnabled = false;
mCondition.signal();
if (mThread.get()) {
mThread->requestExitAndWait();
mThread = NULL;
}
DEINIT_AND_DELETE_OBJ(mVsyncControl);
}
bool VsyncEventObserver::control(bool enabled)
{
ATRACE("enabled = %d on device %d", enabled, mDevice);
if (enabled == mEnabled) {
WTRACE("vsync state %d is not changed", enabled);
return true;
}
Mutex::Autolock _l(mLock);
bool ret = mVsyncControl->control(mDevice, enabled);
if (!ret) {
ETRACE("failed to control (%d) vsync on display %d", enabled, mDevice);
return false;
}
mEnabled = enabled;
mCondition.signal();
return true;
}
bool VsyncEventObserver::threadLoop()
{
do {
// scope for lock
Mutex::Autolock _l(mLock);
while (!mEnabled) {
mCondition.wait(mLock);
if (mExitThread) {
ITRACE("exiting thread loop");
return false;
}
}
} while (0);
if(mEnabled && mDisplayDevice.isConnected()) {
int64_t timestamp;
bool ret = mVsyncControl->wait(mDevice, timestamp);
if (ret == false) {
WTRACE("failed to wait for vsync on display %d, vsync enabled %d", mDevice, mEnabled);
usleep(16000);
return true;
}
// send vsync event notification every hwc.fps_divider
if ((mFpsCounter++) % mDisplayDevice.getFpsDivider() == 0)
mDisplayDevice.onVsync(timestamp);
}
return true;
}
} // namespace intel
} // namesapce android