/*
// 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 <common/utils/HwcTrace.h>
#include <common/observers/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)
{
CTRACE();
}
VsyncEventObserver::~VsyncEventObserver()
{
WARN_IF_NOT_DEINIT();
}
bool VsyncEventObserver::initialize()
{
if (mInitialized) {
WLOGTRACE("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) {
WLOGTRACE("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)
{
ALOGTRACE("enabled = %d on device %d", enabled, mDevice);
if (enabled == mEnabled) {
WLOGTRACE("vsync state %d is not changed", enabled);
return true;
}
Mutex::Autolock _l(mLock);
bool ret = mVsyncControl->control(mDevice, enabled);
if (!ret) {
ELOGTRACE("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) {
ILOGTRACE("exiting thread loop");
return false;
}
}
} while (0);
if(mEnabled && mDisplayDevice.isConnected()) {
int64_t timestamp;
bool ret = mVsyncControl->wait(mDevice, timestamp);
if (ret == false) {
WLOGTRACE("failed to wait for vsync on display %d, vsync enabled %d", mDevice, mEnabled);
usleep(16000);
return true;
}
// notify device
mDisplayDevice.onVsync(timestamp);
}
return true;
}
} // namespace intel
} // namesapce android