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