/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "InputTaskManager.h" #include "VsyncTaskManager.h" #include "nsRefreshDriver.h" namespace mozilla { StaticRefPtr InputTaskManager::gInputTaskManager; void InputTaskManager::EnableInputEventPrioritization() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mInputQueueState == STATE_DISABLED); mInputQueueState = STATE_ENABLED; } void InputTaskManager::FlushInputEventPrioritization() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mInputQueueState == STATE_ENABLED || mInputQueueState == STATE_SUSPEND); mInputQueueState = mInputQueueState == STATE_ENABLED ? STATE_FLUSHING : STATE_SUSPEND; } void InputTaskManager::SuspendInputEventPrioritization() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mInputQueueState == STATE_ENABLED || mInputQueueState == STATE_FLUSHING); mInputQueueState = STATE_SUSPEND; } void InputTaskManager::ResumeInputEventPrioritization() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mInputQueueState == STATE_SUSPEND); mInputQueueState = STATE_ENABLED; } int32_t InputTaskManager::GetPriorityModifierForEventLoopTurn( const MutexAutoLock& aProofOfLock) { // When the state is disabled, the input task that we have is // very likely SuspendInputEventQueue, so here we also use // normal priority as ResumeInputEventQueue, FlushInputEventQueue and // SetInputEventQueueEnabled all uses normal priority, to // ensure the ordering is correct. if (State() == InputTaskManager::STATE_DISABLED) { return static_cast(EventQueuePriority::Normal) - static_cast(EventQueuePriority::InputHigh); } return GetPriorityModifierForEventLoopTurnForStrictVsyncAlignment(); } void InputTaskManager::WillRunTask() { TaskManager::WillRunTask(); mInputPriorityController.WillRunTask(); } int32_t InputTaskManager::GetPriorityModifierForEventLoopTurnForStrictVsyncAlignment() { MOZ_ASSERT(!IsSuspended()); size_t inputCount = PendingTaskCount(); if (inputCount > 0 && mInputPriorityController.ShouldUseHighestPriority(this)) { return static_cast(EventQueuePriority::InputHighest) - static_cast(EventQueuePriority::InputHigh); } if (State() == STATE_FLUSHING || nsRefreshDriver::GetNextTickHint().isNothing()) { return 0; } return static_cast(EventQueuePriority::InputLow) - static_cast(EventQueuePriority::InputHigh); } InputTaskManager::InputPriorityController::InputPriorityController() : mInputVsyncState(InputVsyncState::NoPendingVsync) {} bool InputTaskManager::InputPriorityController::ShouldUseHighestPriority( InputTaskManager* aInputTaskManager) { if (mInputVsyncState == InputVsyncState::HasPendingVsync) { return true; } if (mInputVsyncState == InputVsyncState::RunVsync) { return false; } if (mInputVsyncState == InputVsyncState::NoPendingVsync && VsyncTaskManager::Get()->PendingTaskCount()) { EnterPendingVsyncState(aInputTaskManager->PendingTaskCount()); return true; } return false; } void InputTaskManager::InputPriorityController::EnterPendingVsyncState( uint32_t aNumPendingTasks) { MOZ_ASSERT(mInputVsyncState == InputVsyncState::NoPendingVsync); mInputVsyncState = InputVsyncState::HasPendingVsync; mMaxInputTasksToRun = aNumPendingTasks; mRunInputStartTime = TimeStamp::Now(); } void InputTaskManager::InputPriorityController::WillRunVsync() { if (mInputVsyncState == InputVsyncState::RunVsync || mInputVsyncState == InputVsyncState::HasPendingVsync) { LeavePendingVsyncState(false); } } void InputTaskManager::InputPriorityController::LeavePendingVsyncState( bool aRunVsync) { if (aRunVsync) { MOZ_ASSERT(mInputVsyncState == InputVsyncState::HasPendingVsync); mInputVsyncState = InputVsyncState::RunVsync; } else { mInputVsyncState = InputVsyncState::NoPendingVsync; } mMaxInputTasksToRun = 0; } void InputTaskManager::InputPriorityController::WillRunTask() { switch (mInputVsyncState) { case InputVsyncState::NoPendingVsync: return; case InputVsyncState::HasPendingVsync: MOZ_ASSERT(mMaxInputTasksToRun > 0); --mMaxInputTasksToRun; if (!mMaxInputTasksToRun || TimeStamp::Now() - mRunInputStartTime >= TimeDuration::FromMilliseconds( StaticPrefs::dom_input_event_queue_duration_max())) { LeavePendingVsyncState(true); } return; default: MOZ_DIAGNOSTIC_ASSERT( false, "Shouldn't run this input task when we suppose to run vsync"); return; } } // static void InputTaskManager::Init() { gInputTaskManager = new InputTaskManager(); } } // namespace mozilla