/* * Copyright (C) 2009 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 express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include "EventThread.h" #include "FrameTimeline.h" #include "MessageQueue.h" #ifdef MTK_SF_MSYNC #include "../mediatek/MSync/MSyncSfApi.h" #include #endif #ifdef MTK_SF_MSYNC_3 #include #endif namespace android::impl { #ifdef MTK_SF_MSYNC static bool isShowM2Trace() { static bool enable = false; static bool read = false; if (!read) { enable = android::base::GetBoolProperty("vendor.debug.sf.show_msync2_trace", false); read = true; } return enable; } #define M2_TRACE(x, ...) \ { \ if (isShowM2Trace()) { \ ATRACE_FORMAT("msync2_sf: " x, ##__VA_ARGS__); \ ALOGI("msync2_sf: " x, ##__VA_ARGS__); \ } \ } #endif void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) { if (!mFramePending.exchange(true)) { mVsyncId = vsyncId; mExpectedVsyncTime = expectedVsyncTime; mQueue.mLooper->sendMessage(sp::fromExisting(this), Message()); } } bool MessageQueue::Handler::isFramePending() const { return mFramePending.load(); } void MessageQueue::Handler::handleMessage(const Message&) { mFramePending.store(false); mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime); } MessageQueue::MessageQueue(ICompositor& compositor) : MessageQueue(compositor, sp::make(*this)) {} constexpr bool kAllowNonCallbacks = true; MessageQueue::MessageQueue(ICompositor& compositor, sp handler) : mCompositor(compositor), mLooper(sp::make(kAllowNonCallbacks)), mHandler(std::move(handler)) {} void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) { /*#ifdef MTK_SF_MSYNC { std::lock_guard lock(mVsync.mutex); M2_TRACE("vsyncCallback, vsyncTime=%" PRId64 ", readyTime=%" PRId64, vsyncTime, readyTime); if (mVsyncCanceled && vsyncTime == readyTime) { mVsyncCanceled = false; M2_TRACE("Ignore AOSP vsyncCallback"); return; } } #endif*/ ATRACE_CALL(); // Trace VSYNC-sf mVsync.value = (mVsync.value + 1) % 2; #ifdef MTK_ATRACE_PRESENT_FENCE mVsyncSfToggleTime = systemTime(); #endif const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime); #ifdef MTK_VSYNC_HINT_SUPPORT VSyncHinter::getInstance().onDispSyncEvent(mVSyncInfo, 0); #endif { std::lock_guard lock(mVsync.mutex); mVsync.lastCallbackTime = expectedVsyncTime; mVsync.scheduledFrameTime.reset(); } const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions( {targetWakeupTime, readyTime, vsyncTime})}; mHandler->dispatchFrame(vsyncId, expectedVsyncTime); } void MessageQueue::initVsync(std::shared_ptr dispatch, frametimeline::TokenManager& tokenManager, std::chrono::nanoseconds workDuration) { std::unique_ptr oldRegistration; { std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; mVsync.tokenManager = &tokenManager; oldRegistration = onNewVsyncScheduleLocked(std::move(dispatch)); } // See comments in onNewVsyncSchedule. Today, oldRegistration should be // empty, but nothing prevents us from calling initVsync multiple times, so // go ahead and destruct it outside the lock for safety. oldRegistration.reset(); } void MessageQueue::onNewVsyncSchedule(std::shared_ptr dispatch) { std::unique_ptr oldRegistration; { std::lock_guard lock(mVsync.mutex); oldRegistration = onNewVsyncScheduleLocked(std::move(dispatch)); } // The old registration needs to be deleted after releasing mVsync.mutex to // avoid deadlock. This is because the callback may be running on the timer // thread. In that case, timerCallback sets // VSyncDispatchTimerQueueEntry::mRunning to true, then attempts to lock // mVsync.mutex. But if it's already locked, the VSyncCallbackRegistration's // destructor has to wait until VSyncDispatchTimerQueueEntry::mRunning is // set back to false, but it won't be until mVsync.mutex is released. oldRegistration.reset(); } std::unique_ptr MessageQueue::onNewVsyncScheduleLocked( std::shared_ptr dispatch) { const bool reschedule = mVsync.registration && mVsync.registration->cancel() == scheduler::CancelResult::Cancelled; auto oldRegistration = std::move(mVsync.registration); mVsync.registration = std::make_unique< scheduler::VSyncCallbackRegistration>(std::move(dispatch), std::bind(&MessageQueue::vsyncCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), "sf"); #ifdef MTK_VSYNC_HINT_SUPPORT VSyncHinter::getInstance().fillVSyncInfo(mVSyncInfo, "sf"); #endif if (reschedule) { mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, .earliestVsync = mVsync.lastCallbackTime.ns()}); } return oldRegistration; } void MessageQueue::destroyVsync() { std::lock_guard lock(mVsync.mutex); mVsync.tokenManager = nullptr; mVsync.registration.reset(); } void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { ATRACE_CALL(); std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; mVsync.scheduledFrameTime = mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, .earliestVsync = mVsync.lastCallbackTime.ns()}); } void MessageQueue::waitMessage() { do { IPCThreadState::self()->flushCommands(); int32_t ret = mLooper->pollOnce(-1); switch (ret) { case Looper::POLL_WAKE: case Looper::POLL_CALLBACK: continue; case Looper::POLL_ERROR: ALOGE("Looper::POLL_ERROR"); continue; case Looper::POLL_TIMEOUT: // timeout (should not happen) continue; default: // should not happen ALOGE("Looper::pollOnce() returned unknown status %d", ret); continue; } } while (true); } void MessageQueue::postMessage(sp&& handler) { mLooper->sendMessage(handler, Message()); } #ifdef MTK_SF_SCHEDULE_DELAY //TODO: remove MTK's API void MessageQueue::postMessageDelayed(nsecs_t uptimeDelay, sp&& handler) { mLooper->sendMessageDelayed(uptimeDelay, handler, Message()); } #endif void MessageQueue::postMessageDelayed(sp&& handler, nsecs_t uptimeDelay) { mLooper->sendMessageDelayed(uptimeDelay, handler, Message()); } void MessageQueue::scheduleConfigure() { struct ConfigureHandler : MessageHandler { explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {} void handleMessage(const Message&) override { compositor.configure(); } ICompositor& compositor; }; // TODO(b/241285876): Batch configure tasks that happen within some duration. postMessage(sp::make(mCompositor)); } #ifdef MTK_SF_MSYNC_3 void MessageQueue::cancelScheduledFrame() { std::lock_guard lock(mVsync.mutex); if (mVsync.registration->cancel() == android::scheduler::CancelResult::Cancelled) { ATRACE_NAME("cancelScheduledFrame: name=sf, success"); } else { ATRACE_NAME("cancelScheduledFrame: name=sf, fail"); } } nsecs_t MessageQueue::getCurrentVsyncTime() { std::lock_guard lock(mVsync.mutex); return mVsync.lastCallbackTime.ns(); } #endif void MessageQueue::scheduleFrame() { #ifndef MTK_SF_MSYNC_3 ATRACE_CALL(); #endif std::lock_guard lock(mVsync.mutex); #ifdef MTK_SF_MSYNC_3 ATRACE_FORMAT("%s: name=sf, workDuration=%" PRId64, __func__, mVsync.workDuration.get().count()); #endif mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, .earliestVsync = mVsync.lastCallbackTime.ns()}); } auto MessageQueue::getScheduledFrameTime() const -> std::optional { if (mHandler->isFramePending()) { return Clock::now(); } std::lock_guard lock(mVsync.mutex); if (const auto time = mVsync.scheduledFrameTime) { return Clock::time_point(std::chrono::nanoseconds(*time)); } return std::nullopt; } #ifdef MTK_SF_MSYNC void MessageQueue::msyncVsyncCallback(bool bTriggerVsyncCallback) { nsecs_t wakeupTime = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t vsyncTime; M2_TRACE("msyncVsyncCallback, bTriggerVsyncCallback=%d", bTriggerVsyncCallback); bool bCancelled = true; { std::lock_guard lock(mVsync.mutex); //mVsyncCanceled = true; auto cancelResult = mVsync.registration->cancel(); if (cancelResult == android::scheduler::CancelResult::Cancelled) { // need to set new vsyncTime as last dispached time vsyncTime = wakeupTime + mVsync.workDuration.get().count(); M2_TRACE("cancel scheduleFrame success, new wakeupTime=%" PRId64 " and vsyncTime=%" PRId64, wakeupTime, vsyncTime); if (bTriggerVsyncCallback) { mVsync.registration->setLastDispatchTime(vsyncTime); } } else { M2_TRACE("cancel scheduleFrame failed, error=%d", cancelResult); bCancelled = false; } } if (bCancelled && bTriggerVsyncCallback) { // set readyTime < vsyncTime to indicate the vsync callback from msync2 vsyncCallback(vsyncTime, wakeupTime, vsyncTime-1/*readyTime*/); } } nsecs_t MessageQueue::getLastVsyncWakeupTime() { std::lock_guard lock(mVsync.mutex); return mVsync.lastCallbackTime.ns() - mVsync.workDuration.get().count(); } void MessageQueue::setMSyncSfApi(std::shared_ptr msyncSfApi) { mMSyncSfApi = msyncSfApi; } #endif #ifdef MTK_ATRACE_PRESENT_FENCE nsecs_t MessageQueue::getVsyncSfToggleTime() { return mVsyncSfToggleTime; } #endif } // namespace android::impl