// Copyright 2021 The Android Open Source Project // // 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 expresso or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "VsyncThread.h" #include "aemu/base/system/System.h" namespace gfxstream { VsyncThread::VsyncThread(uint64_t vsyncPeriodNs) : mPeriodNs(vsyncPeriodNs), mThread([this] { threadFunc(); }) { mThread.start(); } VsyncThread::~VsyncThread() { exit(); } void VsyncThread::schedule(VsyncTask task) { mChannel.send({ CommandType::Default, task }); } void VsyncThread::setPeriod(uint64_t newPeriod) { mChannel.send({ CommandType::ChangePeriod, {}, newPeriod }); } void VsyncThread::exit() { mChannel.send({ CommandType::Exit }); mThread.wait(); } void VsyncThread::threadFunc() { VsyncThreadCommand currentCommand; uint64_t lastTimeUs = ~0ULL; uint64_t phasedWaitTimeUs; uint64_t currentUs; while (true) { uint64_t periodUs = mPeriodNs / 1000ULL; currentUs = android::base::getHighResTimeUs(); if (lastTimeUs == ~0ULL) { phasedWaitTimeUs = currentUs + periodUs; } else { phasedWaitTimeUs = periodUs * ((currentUs - lastTimeUs) / periodUs + 1) + lastTimeUs; } android::base::sleepToUs(phasedWaitTimeUs); lastTimeUs = phasedWaitTimeUs; while (mChannel.tryReceive(¤tCommand)) { switch (currentCommand.type) { case CommandType::Exit: return; case CommandType::ChangePeriod: mPeriodNs = currentCommand.newPeriod; break; case CommandType::Default: default: currentCommand.task(mCount); } } ++mCount; } } } // namespace gfxstream