summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/InputTaskManager.h
blob: 2f920a31ae54bcaa812411ab22efbc6eaf01c570 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* -*- 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/. */

#ifndef mozilla_InputTaskManager_h
#define mozilla_InputTaskManager_h

#include "nsTArray.h"
#include "nsXULAppAPI.h"
#include "TaskController.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StaticPrefs_dom.h"

namespace mozilla {

class InputTaskManager : public TaskManager {
 public:
  int32_t GetPriorityModifierForEventLoopTurn(
      const MutexAutoLock& aProofOfLock) final;
  void WillRunTask() final;

  enum InputEventQueueState {
    STATE_DISABLED,
    STATE_FLUSHING,
    STATE_SUSPEND,
    STATE_ENABLED
  };

  void EnableInputEventPrioritization();
  void FlushInputEventPrioritization();
  void SuspendInputEventPrioritization();
  void ResumeInputEventPrioritization();

  InputEventQueueState State() { return mInputQueueState; }

  void SetState(InputEventQueueState aState) { mInputQueueState = aState; }

  static InputTaskManager* Get() { return gInputTaskManager.get(); }
  static void Cleanup() { gInputTaskManager = nullptr; }
  static void Init();

  bool IsSuspended(const MutexAutoLock& aProofOfLock) override {
    MOZ_ASSERT(NS_IsMainThread());
    return mInputQueueState == STATE_SUSPEND || mSuspensionLevel > 0;
  }

  bool IsSuspended() {
    MOZ_ASSERT(NS_IsMainThread());
    return mSuspensionLevel > 0;
  }

  void IncSuspensionLevel() {
    MOZ_ASSERT(NS_IsMainThread());
    ++mSuspensionLevel;
  }

  void DecSuspensionLevel() {
    MOZ_ASSERT(NS_IsMainThread());
    --mSuspensionLevel;
  }

  static bool CanSuspendInputEvent() {
    // Ensure it's content process because InputTaskManager only
    // works in e10s.
    //
    // Input tasks will have nullptr as their task manager when the
    // event queue state is STATE_DISABLED, so we can't suspend
    // input events.
    return XRE_IsContentProcess() &&
           StaticPrefs::dom_input_events_canSuspendInBCG_enabled() &&
           InputTaskManager::Get()->State() !=
               InputEventQueueState::STATE_DISABLED;
  }

  void NotifyVsync() { mInputPriorityController.WillRunVsync(); }

 private:
  InputTaskManager() : mInputQueueState(STATE_DISABLED) {}

  class InputPriorityController {
   public:
    InputPriorityController();
    // Determines whether we should use the highest input priority for input
    // tasks
    bool ShouldUseHighestPriority(InputTaskManager*);

    void WillRunVsync();

    // Gets called when a input task is going to run; If the current
    // input vsync state is `HasPendingVsync`, determines whether we
    // should continue running input tasks or leave the `HasPendingVsync` state
    // based on
    //    1. Whether we still have time to process input tasks
    //    2. Whether we have processed the max number of tasks that
    //    we should process.
    void WillRunTask();

   private:
    // Used to represents the relationship between Input and Vsync.
    //
    // HasPendingVsync: There are pending vsync tasks and we are using
    // InputHighest priority for inputs.
    // NoPendingVsync: No pending vsync tasks and no need to use InputHighest
    // priority.
    // RunVsync: Finished running input tasks and the vsync task
    // should be run.
    enum class InputVsyncState {
      HasPendingVsync,
      NoPendingVsync,
      RunVsync,
    };

    void EnterPendingVsyncState(uint32_t aNumPendingTasks);
    void LeavePendingVsyncState(bool aRunVsync);

    // Stores the number of pending input tasks when we enter the
    // InputVsyncState::HasPendingVsync state.
    uint32_t mMaxInputTasksToRun = 0;

    InputVsyncState mInputVsyncState;

    TimeStamp mRunInputStartTime;
  };

  int32_t GetPriorityModifierForEventLoopTurnForStrictVsyncAlignment();

  Atomic<InputEventQueueState> mInputQueueState;

  static StaticRefPtr<InputTaskManager> gInputTaskManager;

  // Number of BCGs have asked InputTaskManager to suspend input events
  uint32_t mSuspensionLevel = 0;

  InputPriorityController mInputPriorityController;
};

}  // namespace mozilla

#endif  // mozilla_InputTaskManager_h