/* // 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 <SoftVsyncObserver.h> #include <IDisplayDevice.h> extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); namespace android { namespace intel { SoftVsyncObserver::SoftVsyncObserver(IDisplayDevice& disp) : mDisplayDevice(disp), mDevice(IDisplayDevice::DEVICE_COUNT), mEnabled(false), mRefreshRate(60), // default 60 frames per second mRefreshPeriod(0), mLock(), mCondition(), mNextFakeVSync(0), mExitThread(false), mInitialized(false) { } SoftVsyncObserver::~SoftVsyncObserver() { WARN_IF_NOT_DEINIT(); } bool SoftVsyncObserver::initialize() { if (mInitialized) { WTRACE("object has been initialized"); return true; } mExitThread = false; mEnabled = false; mRefreshRate = 60/mDisplayDevice.getFpsDivider(); mDevice = mDisplayDevice.getType(); mThread = new VsyncEventPollThread(this); if (!mThread.get()) { DEINIT_AND_RETURN_FALSE("failed to create vsync event poll thread."); } mThread->run("SoftVsyncObserver", PRIORITY_URGENT_DISPLAY); mInitialized = true; return true; } void SoftVsyncObserver::deinitialize() { if (mEnabled) { WTRACE("soft vsync is still enabled"); control(false); } mExitThread = true; mCondition.signal(); if (mThread.get()) { mThread->requestExitAndWait(); mThread = NULL; } mInitialized = false; } void SoftVsyncObserver::setRefreshRate(int rate) { if (mEnabled) { WTRACE("too late to set refresh rate"); } else if (rate < 1 || rate > 120) { WTRACE("invalid refresh rate %d", rate); } else { mRefreshRate = rate; } } bool SoftVsyncObserver::control(bool enabled) { if (enabled == mEnabled) { WTRACE("vsync state %d is not changed", enabled); return true; } if (enabled) { mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); mNextFakeVSync = systemTime(CLOCK_MONOTONIC) + mRefreshPeriod; } mEnabled = enabled; mCondition.signal(); return true; } bool SoftVsyncObserver::threadLoop() { { // scope for lock Mutex::Autolock _l(mLock); while (!mEnabled) { mCondition.wait(mLock); if (mExitThread) { ITRACE("exiting thread loop"); return false; } } } const nsecs_t period = mRefreshPeriod * mDisplayDevice.getFpsDivider(); const nsecs_t now = systemTime(CLOCK_MONOTONIC); nsecs_t next_vsync = mNextFakeVSync; nsecs_t sleep = next_vsync - now; if (sleep < 0) { // we missed, find where the next vsync should be sleep = (period - ((now - next_vsync) % period)); next_vsync = now + sleep; } mNextFakeVSync = next_vsync + period; struct timespec spec; spec.tv_sec = next_vsync / 1000000000; spec.tv_nsec = next_vsync % 1000000000; int err; do { err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); } while (err < 0 && errno == EINTR); if (err == 0) { mDisplayDevice.onVsync(next_vsync); } return true; } } // namespace intel } // namesapce android