diff options
author | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 17:22:40 +0000 |
---|---|---|
committer | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 17:22:40 +0000 |
commit | 5a992e9cc29dabab761193bbbec07c8c40a80acc (patch) | |
tree | 333906ffc4700187adccd1613c45f66a398112e8 /content/renderer | |
parent | 1847ce79a71a755e276070553eddd08f969d0e43 (diff) | |
download | chromium_src-5a992e9cc29dabab761193bbbec07c8c40a80acc.zip chromium_src-5a992e9cc29dabab761193bbbec07c8c40a80acc.tar.gz chromium_src-5a992e9cc29dabab761193bbbec07c8c40a80acc.tar.bz2 |
Only throttle input to the render widget for heavy input handlers
This tracks the total time spent handling input on the main thread
for the current frame and only throttles input events once the
total time has reached a threshold.
If a cheap and reliable HighResNow is not available, the handlers
are assumed to be heavy.
TEST=Manually run MapsGL in a small window so it hits 60fps. Verified
panning tracks pointer more closely when using a 120Hz mouse.
Also tested with http://thj.no/personal/latency_test_case.html. This
patch produces visibly lower latency and allows the app to receive
more mouse move events to produce smoother curves.
BUG=305210
Review URL: https://codereview.chromium.org/25687004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230458 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
-rw-r--r-- | content/renderer/render_widget.cc | 45 | ||||
-rw-r--r-- | content/renderer/render_widget.h | 4 |
2 files changed, 40 insertions, 9 deletions
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 742557e..76b3fe9 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -141,6 +141,13 @@ ui::TextInputMode ConvertInputMode( return it->second; } +// TODO(brianderson): Replace the hard-coded threshold with a fraction of +// the BeginMainFrame interval. +// 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to +// be spent in input hanlders before input starts getting throttled. +static const base::TimeDelta kInputHandlingTimeThrottlingThreshold = + base::TimeDelta::FromMicroseconds(4166); + } // namespace namespace content { @@ -1051,6 +1058,10 @@ void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event, return; } + base::TimeTicks start_time; + if (base::TimeTicks::IsHighResNowFastAndReliable()) + start_time = base::TimeTicks::HighResNow(); + const char* const event_name = WebInputEventTraits::GetName(input_event->type); TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent", @@ -1130,7 +1141,7 @@ void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event, input_event->type, ack_result, latency_info); - bool event_type_gets_rate_limited = + bool event_type_can_be_rate_limited = input_event->type == WebInputEvent::MouseMove || input_event->type == WebInputEvent::MouseWheel || input_event->type == WebInputEvent::TouchMove; @@ -1141,9 +1152,23 @@ void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event, compositor_->commitRequested(); } - if (event_type_gets_rate_limited && frame_pending && !is_hidden_) { + // If we don't have a fast and accurate HighResNow, we assume the input + // handlers are heavy and rate limit them. + bool rate_limiting_wanted = true; + if (base::TimeTicks::IsHighResNowFastAndReliable()) { + base::TimeTicks end_time = base::TimeTicks::HighResNow(); + total_input_handling_time_this_frame_ += (end_time - start_time); + rate_limiting_wanted = (total_input_handling_time_this_frame_ > + kInputHandlingTimeThrottlingThreshold); + } + + if (rate_limiting_wanted && event_type_can_be_rate_limited && + frame_pending && !is_hidden_) { // We want to rate limit the input events in this case, so we'll wait for // painting to finish before ACKing this message. + TRACE_EVENT_INSTANT0("renderer", + "RenderWidget::OnHandleInputEvent ack throttled", + TRACE_EVENT_SCOPE_THREAD); if (pending_input_event_ack_) { // As two different kinds of events could cause us to postpone an ack // we send it now, if we have one pending. The Browser should never @@ -1399,11 +1424,15 @@ void RenderWidget::InvalidationCallback() { DoDeferredUpdateAndSendInputAck(); } -void RenderWidget::DoDeferredUpdateAndSendInputAck() { - DoDeferredUpdate(); - +void RenderWidget::FlushPendingInputEventAck() { if (pending_input_event_ack_) Send(pending_input_event_ack_.release()); + total_input_handling_time_this_frame_ = base::TimeDelta(); +} + +void RenderWidget::DoDeferredUpdateAndSendInputAck() { + DoDeferredUpdate(); + FlushPendingInputEventAck(); } void RenderWidget::DoDeferredUpdate() { @@ -1625,8 +1654,7 @@ void RenderWidget::DoDeferredUpdate() { // UpdateReply message so we can receive another input event before the // UpdateRect_ACK on platforms where the UpdateRect_ACK is sent from within // the UpdateRect IPC message handler. - if (pending_input_event_ack_) - Send(pending_input_event_ack_.release()); + FlushPendingInputEventAck(); // If Composite() called SwapBuffers, pending_update_params_ will be reset (in // OnSwapBuffersPosted), meaning a message has been added to the @@ -1845,8 +1873,7 @@ void RenderWidget::willBeginCompositorFrame() { void RenderWidget::didBecomeReadyForAdditionalInput() { TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput"); - if (pending_input_event_ack_) - Send(pending_input_event_ack_.release()); + FlushPendingInputEventAck(); } void RenderWidget::DidCommitCompositorFrame() { diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 1299613..1a14d2c 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h @@ -293,6 +293,7 @@ class CONTENT_EXPORT RenderWidget void AnimationCallback(); void AnimateIfNeeded(); void InvalidationCallback(); + void FlushPendingInputEventAck(); void DoDeferredUpdateAndSendInputAck(); void DoDeferredUpdate(); void DoDeferredClose(); @@ -712,6 +713,9 @@ class CONTENT_EXPORT RenderWidget scoped_ptr<IPC::Message> pending_input_event_ack_; + // The time spent in input handlers this frame. Used to throttle input acks. + base::TimeDelta total_input_handling_time_this_frame_; + // Indicates if the next sequence of Char events should be suppressed or not. bool suppress_next_char_events_; |