summaryrefslogtreecommitdiffstats
path: root/content/renderer/scheduler/renderer_scheduler_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/renderer/scheduler/renderer_scheduler_impl.cc')
-rw-r--r--content/renderer/scheduler/renderer_scheduler_impl.cc131
1 files changed, 104 insertions, 27 deletions
diff --git a/content/renderer/scheduler/renderer_scheduler_impl.cc b/content/renderer/scheduler/renderer_scheduler_impl.cc
index 26cbd4e..6d5c8a0 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl.cc
+++ b/content/renderer/scheduler/renderer_scheduler_impl.cc
@@ -30,6 +30,8 @@ RendererSchedulerImpl::RendererSchedulerImpl(
loading_task_runner_(
task_queue_manager_->TaskRunnerForQueue(LOADING_TASK_QUEUE)),
current_policy_(NORMAL_PRIORITY_POLICY),
+ last_input_type_(blink::WebInputEvent::Undefined),
+ input_stream_state_(INPUT_INACTIVE),
policy_may_need_update_(&incoming_signals_lock_),
weak_factory_(this) {
weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr();
@@ -127,7 +129,7 @@ void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread(
// that the user is doing something requiring a smooth frame rate.
if (web_input_event.type == blink::WebInputEvent::MouseMove &&
(web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
- UpdateForInputEvent();
+ UpdateForInputEvent(web_input_event.type);
return;
}
// Ignore all other mouse events because they probably don't signal user
@@ -139,21 +141,28 @@ void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread(
blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) {
return;
}
- UpdateForInputEvent();
+ UpdateForInputEvent(web_input_event.type);
}
void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() {
- UpdateForInputEvent();
+ UpdateForInputEvent(blink::WebInputEvent::Undefined);
}
-void RendererSchedulerImpl::UpdateForInputEvent() {
+void RendererSchedulerImpl::UpdateForInputEvent(
+ blink::WebInputEvent::Type type) {
base::AutoLock lock(incoming_signals_lock_);
- if (last_input_time_.is_null()) {
- // Update scheduler policy if should start a new compositor policy mode.
+
+ InputStreamState new_input_stream_state =
+ ComputeNewInputStreamState(input_stream_state_, type, last_input_type_);
+
+ if (input_stream_state_ != new_input_stream_state) {
+ // Update scheduler policy if we should start a new policy mode.
+ input_stream_state_ = new_input_stream_state;
policy_may_need_update_.SetLocked(true);
PostUpdatePolicyOnControlRunner(base::TimeDelta());
}
last_input_time_ = Now();
+ last_input_type_ = type;
}
bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() {
@@ -162,7 +171,10 @@ bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() {
return false;
MaybeUpdatePolicy();
- return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY;
+ // The touchstart and compositor policies indicate a strong likelihood of
+ // high-priority work in the near future.
+ return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY ||
+ SchedulerPolicy() == TOUCHSTART_PRIORITY_POLICY;
}
bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
@@ -171,13 +183,13 @@ bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
return false;
MaybeUpdatePolicy();
- // We only yield if we are in the compositor priority and there is compositor
- // work outstanding. Note: even though the control queue is higher priority
- // we don't yield for it since these tasks are not user-provided work and they
- // are only intended to run before the next task, not interrupt the tasks.
- // Note: This function could conceivably be implemented in terms of
- // |IsHighPriorityWorkAnticipated|, but for clarity is not.
- return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY &&
+ // We only yield if we are in the touchstart/compositor priority and there
+ // is input/compositor work outstanding. Note: even though the control queue
+ // is higher priority we don't yield for it since these tasks are not
+ // user-provided work and they are only intended to run before the next task,
+ // not interrupt the tasks.
+ return (SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY ||
+ SchedulerPolicy() == TOUCHSTART_PRIORITY_POLICY) &&
!task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE);
}
@@ -215,20 +227,22 @@ void RendererSchedulerImpl::UpdatePolicy() {
policy_may_need_update_.SetLocked(false);
Policy new_policy = NORMAL_PRIORITY_POLICY;
- if (!last_input_time_.is_null()) {
- base::TimeDelta compositor_priority_duration =
- base::TimeDelta::FromMilliseconds(kCompositorPriorityAfterTouchMillis);
- base::TimeTicks compositor_priority_end(last_input_time_ +
- compositor_priority_duration);
- now = Now();
- if (compositor_priority_end > now) {
- PostUpdatePolicyOnControlRunner(compositor_priority_end - now);
- new_policy = COMPOSITOR_PRIORITY_POLICY;
+ if (input_stream_state_ != INPUT_INACTIVE) {
+ base::TimeDelta new_priority_duration =
+ base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
+ base::TimeTicks new_priority_end(last_input_time_ + new_priority_duration);
+ base::TimeDelta time_left_in_policy = new_priority_end - Now();
+ if (time_left_in_policy > base::TimeDelta()) {
+ PostUpdatePolicyOnControlRunner(time_left_in_policy);
+ new_policy =
+ input_stream_state_ == INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE
+ ? TOUCHSTART_PRIORITY_POLICY
+ : COMPOSITOR_PRIORITY_POLICY;
} else {
- // Null out last_input_time_ to ensure
- // DidReceiveInputEventOnCompositorThread will post an
- // UpdatePolicy task when it's next called.
- last_input_time_ = base::TimeTicks();
+ // Reset |input_stream_state_| to ensure
+ // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
+ // when it's next called.
+ input_stream_state_ = INPUT_INACTIVE;
}
}
@@ -244,6 +258,11 @@ void RendererSchedulerImpl::UpdatePolicy() {
renderer_task_queue_selector_->SetQueuePriority(
LOADING_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
break;
+ case TOUCHSTART_PRIORITY_POLICY:
+ renderer_task_queue_selector_->SetQueuePriority(
+ COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY);
+ renderer_task_queue_selector_->DisableQueue(LOADING_TASK_QUEUE);
+ break;
case NORMAL_PRIORITY_POLICY:
renderer_task_queue_selector_->SetQueuePriority(
COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY);
@@ -251,6 +270,10 @@ void RendererSchedulerImpl::UpdatePolicy() {
LOADING_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY);
break;
}
+ DCHECK(renderer_task_queue_selector_->IsQueueEnabled(COMPOSITOR_TASK_QUEUE));
+ if (new_policy != TOUCHSTART_PRIORITY_POLICY)
+ DCHECK(renderer_task_queue_selector_->IsQueueEnabled(LOADING_TASK_QUEUE));
+
current_policy_ = new_policy;
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
@@ -341,6 +364,23 @@ const char* RendererSchedulerImpl::PolicyToString(Policy policy) {
return "normal";
case COMPOSITOR_PRIORITY_POLICY:
return "compositor";
+ case TOUCHSTART_PRIORITY_POLICY:
+ return "touchstart";
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
+const char* RendererSchedulerImpl::InputStreamStateToString(
+ InputStreamState state) {
+ switch (state) {
+ case INPUT_INACTIVE:
+ return "inactive";
+ case INPUT_ACTIVE:
+ return "active";
+ case INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE:
+ return "active_and_awaiting_touchstart_response";
default:
NOTREACHED();
return nullptr;
@@ -358,6 +398,8 @@ RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
new base::trace_event::TracedValue();
state->SetString("current_policy", PolicyToString(current_policy_));
+ state->SetString("input_stream_state",
+ InputStreamStateToString(input_stream_state_));
state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
state->SetDouble("last_input_time",
(last_input_time_ - base::TimeTicks()).InMillisecondsF());
@@ -368,4 +410,39 @@ RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
return state;
}
+RendererSchedulerImpl::InputStreamState
+RendererSchedulerImpl::ComputeNewInputStreamState(
+ InputStreamState current_state,
+ blink::WebInputEvent::Type new_input_type,
+ blink::WebInputEvent::Type last_input_type) {
+ switch (new_input_type) {
+ case blink::WebInputEvent::TouchStart:
+ return INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE;
+
+ case blink::WebInputEvent::TouchMove:
+ // Observation of consecutive touchmoves is a strong signal that the page
+ // is consuming the touch sequence, in which case touchstart response
+ // prioritization is no longer necessary. Otherwise, the initial touchmove
+ // should preserve the touchstart response pending state.
+ if (current_state == INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE) {
+ return last_input_type == blink::WebInputEvent::TouchMove
+ ? INPUT_ACTIVE
+ : INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE;
+ }
+ break;
+
+ case blink::WebInputEvent::GestureTapDown:
+ case blink::WebInputEvent::GestureShowPress:
+ case blink::WebInputEvent::GestureFlingCancel:
+ case blink::WebInputEvent::GestureScrollEnd:
+ // With no observable effect, these meta events do not indicate a
+ // meaningful touchstart response and should not impact task priority.
+ return current_state;
+
+ default:
+ break;
+ }
+ return INPUT_ACTIVE;
+}
+
} // namespace content