1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_InputTaskManager_h 8 #define mozilla_InputTaskManager_h 9 10 #include "nsXULAppAPI.h" 11 #include "TaskController.h" 12 #include "mozilla/StaticPtr.h" 13 #include "mozilla/StaticPrefs_dom.h" 14 #include "nsXULAppAPI.h" 15 16 namespace mozilla { 17 18 class InputTaskManager : public TaskManager { 19 public: 20 int32_t GetPriorityModifierForEventLoopTurn( 21 const MutexAutoLock& aProofOfLock) final; 22 void WillRunTask() final; 23 void DidRunTask() final; 24 25 enum InputEventQueueState { 26 STATE_DISABLED, 27 STATE_FLUSHING, 28 STATE_SUSPEND, 29 STATE_ENABLED 30 }; 31 32 void EnableInputEventPrioritization(); 33 void FlushInputEventPrioritization(); 34 void SuspendInputEventPrioritization(); 35 void ResumeInputEventPrioritization(); 36 State()37 InputEventQueueState State() { return mInputQueueState; } 38 SetState(InputEventQueueState aState)39 void SetState(InputEventQueueState aState) { mInputQueueState = aState; } 40 InputHandlingStartTime()41 TimeStamp InputHandlingStartTime() { return mInputHandlingStartTime; } 42 SetInputHandlingStartTime(TimeStamp aStartTime)43 void SetInputHandlingStartTime(TimeStamp aStartTime) { 44 mInputHandlingStartTime = aStartTime; 45 } 46 Get()47 static InputTaskManager* Get() { return gInputTaskManager.get(); } Cleanup()48 static void Cleanup() { gInputTaskManager = nullptr; } 49 static void Init(); 50 IsSuspended(const MutexAutoLock & aProofOfLock)51 bool IsSuspended(const MutexAutoLock& aProofOfLock) override { 52 MOZ_ASSERT(NS_IsMainThread()); 53 return mInputQueueState == STATE_SUSPEND || mSuspensionLevel > 0; 54 } 55 IsSuspended()56 bool IsSuspended() { 57 MOZ_ASSERT(NS_IsMainThread()); 58 return mSuspensionLevel > 0; 59 } 60 IncSuspensionLevel()61 void IncSuspensionLevel() { 62 MOZ_ASSERT(NS_IsMainThread()); 63 ++mSuspensionLevel; 64 } 65 DecSuspensionLevel()66 void DecSuspensionLevel() { 67 MOZ_ASSERT(NS_IsMainThread()); 68 --mSuspensionLevel; 69 } 70 CanSuspendInputEvent()71 static bool CanSuspendInputEvent() { 72 // Ensure it's content process because InputTaskManager only 73 // works in e10s. 74 // 75 // Input tasks will have nullptr as their task manager when the 76 // event queue state is STATE_DISABLED, so we can't suspend 77 // input events. 78 return XRE_IsContentProcess() && 79 StaticPrefs::dom_input_events_canSuspendInBCG_enabled() && 80 InputTaskManager::Get()->State() != 81 InputEventQueueState::STATE_DISABLED; 82 } 83 NotifyVsync()84 void NotifyVsync() { 85 MOZ_ASSERT(StaticPrefs::dom_input_events_strict_input_vsync_alignment()); 86 mInputPriorityController.WillRunVsync(); 87 } 88 89 private: InputTaskManager()90 InputTaskManager() : mInputQueueState(STATE_DISABLED) {} 91 92 class InputPriorityController { 93 public: 94 InputPriorityController(); 95 // Determines whether we should use the highest input priority for input 96 // tasks 97 bool ShouldUseHighestPriority(InputTaskManager*); 98 99 void WillRunVsync(); 100 101 // Gets called when a input task is going to run; If the current 102 // input vsync state is `HasPendingVsync`, determines whether we 103 // should continue running input tasks or leave the `HasPendingVsync` state 104 // based on 105 // 1. Whether we still have time to process input tasks 106 // 2. Whether we have processed the max number of tasks that 107 // we should process. 108 void WillRunTask(); 109 110 private: 111 // Used to represents the relationship between Input and Vsync. 112 // 113 // HasPendingVsync: There are pending vsync tasks and we are using 114 // InputHighest priority for inputs. 115 // NoPendingVsync: No pending vsync tasks and no need to use InputHighest 116 // priority. 117 // RunVsync: Finished running input tasks and the vsync task 118 // should be run. 119 enum class InputVsyncState { 120 HasPendingVsync, 121 NoPendingVsync, 122 RunVsync, 123 }; 124 125 void EnterPendingVsyncState(uint32_t aNumPendingTasks); 126 void LeavePendingVsyncState(bool aRunVsync); 127 128 // Stores the number of pending input tasks when we enter the 129 // InputVsyncState::HasPendingVsync state. 130 uint32_t mMaxInputTasksToRun = 0; 131 132 bool mIsInitialized; 133 InputVsyncState mInputVsyncState; 134 135 TimeStamp mRunInputStartTime; 136 TimeDuration mMaxInputHandlingDuration; 137 }; 138 139 int32_t GetPriorityModifierForEventLoopTurnForStrictVsyncAlignment(); 140 141 TimeStamp mInputHandlingStartTime; 142 Atomic<InputEventQueueState> mInputQueueState; 143 AutoTArray<TimeStamp, 4> mStartTimes; 144 145 static StaticRefPtr<InputTaskManager> gInputTaskManager; 146 147 // Number of BCGs have asked InputTaskManager to suspend input events 148 uint32_t mSuspensionLevel = 0; 149 150 InputPriorityController mInputPriorityController; 151 }; 152 153 } // namespace mozilla 154 155 #endif // mozilla_InputTaskManager_h 156