[cc] Add a way to request an "urgent" main frame
When main frame updates are throttled to a lower framerate than impl frames, some use cases may regress. This is partly intentionnal, for instance requestAnimationFrame() should run at a lower framerate. However, some updates (e.g. reacting to an input event) would benefit from being processed at the next opportunity. This CL adds the CC-side mechanism for it. It is split from a larger CL, which adds the blink-side plumbing, as well as use cases. Bug: 379678455 Change-Id: Idc662418829fb33e8d534063cc888a9572070526 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6163465 Commit-Queue: Benoit Lize <lizeb@chromium.org> Reviewed-by: Jonathan Ross <jonross@chromium.org> Cr-Commit-Position: refs/heads/main@{#1407060}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
10fe5d4663
commit
eab48df497
cc
scheduler
scheduler.ccscheduler.hscheduler_state_machine.ccscheduler_state_machine.hscheduler_state_machine_unittest.cc
test
trees
components/viz/service/layers
@ -164,8 +164,8 @@ void Scheduler::NotifyPaintWorkletStateChange(PaintWorkletState state) {
|
||||
ProcessScheduledActions();
|
||||
}
|
||||
|
||||
void Scheduler::SetNeedsBeginMainFrame() {
|
||||
state_machine_.SetNeedsBeginMainFrame();
|
||||
void Scheduler::SetNeedsBeginMainFrame(bool now) {
|
||||
state_machine_.SetNeedsBeginMainFrame(now);
|
||||
ProcessScheduledActions();
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,12 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
|
||||
// source to be told to send BeginFrames to this client so that this client
|
||||
// can send a CompositorFrame to the display compositor with appropriate
|
||||
// timing.
|
||||
void SetNeedsBeginMainFrame();
|
||||
//
|
||||
// Set `now` to true if the BeginMainFrame() should not be throttled, but
|
||||
// happen as the next opportunity. This is useful when main frame updates are
|
||||
// running at a lower rate than compositor frames, but we don't want to wait
|
||||
// (e.g. there is an input event).
|
||||
void SetNeedsBeginMainFrame(bool now = false);
|
||||
|
||||
// Requests a single impl frame (after the current frame if there is one
|
||||
// active).
|
||||
|
@ -1612,8 +1612,12 @@ bool SchedulerStateMachine::ImplLatencyTakesPriority() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SchedulerStateMachine::SetNeedsBeginMainFrame() {
|
||||
void SchedulerStateMachine::SetNeedsBeginMainFrame(bool now) {
|
||||
needs_begin_main_frame_ = true;
|
||||
|
||||
if (now) {
|
||||
last_sent_begin_main_frame_time_ = base::TimeTicks();
|
||||
}
|
||||
}
|
||||
|
||||
void SchedulerStateMachine::SetNeedsOneBeginImplFrame() {
|
||||
@ -1647,7 +1651,7 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
|
||||
// the next BeginMainFrame after the deferred commit timeout will cause
|
||||
// a commit, but it might come later than optimal.
|
||||
begin_main_frame_state_ = BeginMainFrameState::IDLE;
|
||||
SetNeedsBeginMainFrame();
|
||||
SetNeedsBeginMainFrame(/* now = */ false);
|
||||
break;
|
||||
case CommitEarlyOutReason::kFinishedNoUpdates:
|
||||
WillCommit(/*commit_had_no_updates=*/true);
|
||||
@ -1662,7 +1666,7 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
|
||||
case CommitEarlyOutReason::kAbortedNotVisible:
|
||||
case CommitEarlyOutReason::kAbortedDeferredMainFrameUpdate:
|
||||
case CommitEarlyOutReason::kAbortedDeferredCommit:
|
||||
SetNeedsBeginMainFrame();
|
||||
SetNeedsBeginMainFrame(/* now = */ false);
|
||||
break;
|
||||
case CommitEarlyOutReason::kFinishedNoUpdates:
|
||||
commit_count_++;
|
||||
|
@ -271,7 +271,13 @@ class CC_EXPORT SchedulerStateMachine {
|
||||
// Indicates that a new begin main frame flow needs to be performed, either
|
||||
// to pull updates from the main thread to the impl, or to push deltas from
|
||||
// the impl thread to main.
|
||||
void SetNeedsBeginMainFrame();
|
||||
//
|
||||
// If `now` is true, then the BeginMainFrame() update is not throttled, and
|
||||
// the next BeginMainFrame() will be sent at the next opportunity, regardless
|
||||
// of the interval since the last one. This is to be used in cases where
|
||||
// `SetThrottleMainFrames()` has been called, and we have an "urgent" update
|
||||
// that should not wait more than necessary.
|
||||
void SetNeedsBeginMainFrame(bool now = false);
|
||||
bool needs_begin_main_frame() const { return needs_begin_main_frame_; }
|
||||
|
||||
void SetMainThreadWantsBeginMainFrameNotExpectedMessages(bool new_state);
|
||||
|
@ -1,22 +1,24 @@
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cc/scheduler/scheduler_state_machine.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "cc/metrics/begin_main_frame_metrics.h"
|
||||
#ifdef UNSAFE_BUFFERS_BUILD
|
||||
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
|
||||
#pragma allow_unsafe_buffers
|
||||
#endif
|
||||
|
||||
#include "base/test/gtest_util.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "cc/base/features.h"
|
||||
#include "cc/metrics/begin_main_frame_metrics.h"
|
||||
#include "cc/scheduler/scheduler.h"
|
||||
#include "components/viz/common/frame_sinks/begin_frame_args.h"
|
||||
#include "components/viz/test/begin_frame_args_test.h"
|
||||
@ -1153,6 +1155,51 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
|
||||
EXPECT_FALSE(state.needs_redraw());
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool RunOneFrameAndReturnWhetherMainFrameIsIssued(StateMachine& state) {
|
||||
state.IssueNextBeginImplFrame();
|
||||
// If we send a BeginMainFrame(), simulate the fast path, where main is fast
|
||||
// enough to catch the next deadline.
|
||||
bool send_begin_main_frame = state.ShouldSendBeginMainFrame();
|
||||
if (state.ShouldSendBeginMainFrame()) {
|
||||
send_begin_main_frame = true;
|
||||
EXPECT_ACTION_UPDATE_STATE(
|
||||
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
|
||||
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
|
||||
EXPECT_FALSE(state.NeedsCommit());
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
state.NotifyReadyToCommit();
|
||||
EXPECT_MAIN_FRAME_STATE(
|
||||
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
|
||||
state.NotifyReadyToActivate();
|
||||
EXPECT_ACTION_UPDATE_STATE(
|
||||
SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
|
||||
EXPECT_TRUE(state.active_tree_needs_first_draw());
|
||||
EXPECT_TRUE(state.needs_redraw());
|
||||
} else {
|
||||
// Still need to require a draw, otherwise nothing will happen below.
|
||||
state.SetNeedsRedraw(true);
|
||||
}
|
||||
|
||||
// Expect to do nothing until BeginImplFrame deadline
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
state.OnBeginImplFrameDeadline();
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
|
||||
state.DidSubmitCompositorFrame();
|
||||
state.DidReceiveCompositorFrameAck();
|
||||
|
||||
// Should be synchronized, no draw needed, no action needed.
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
|
||||
EXPECT_FALSE(state.needs_redraw());
|
||||
|
||||
return send_begin_main_frame;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(SchedulerStateMachineTest, TestMainFrameThrottling) {
|
||||
SchedulerSettings default_scheduler_settings;
|
||||
StateMachine state(default_scheduler_settings);
|
||||
@ -1164,50 +1211,55 @@ TEST(SchedulerStateMachineTest, TestMainFrameThrottling) {
|
||||
int begin_main_frame_count = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
state.SetNeedsBeginMainFrame();
|
||||
state.IssueNextBeginImplFrame();
|
||||
|
||||
// If we send a BeginMainFrame(), simulate the fast path, where main is fast
|
||||
// enough to catch the next deadline.
|
||||
if (state.ShouldSendBeginMainFrame()) {
|
||||
begin_main_frame_count += 1;
|
||||
EXPECT_ACTION_UPDATE_STATE(
|
||||
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
|
||||
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
|
||||
EXPECT_FALSE(state.NeedsCommit());
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
state.NotifyReadyToCommit();
|
||||
EXPECT_MAIN_FRAME_STATE(
|
||||
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
|
||||
state.NotifyReadyToActivate();
|
||||
EXPECT_ACTION_UPDATE_STATE(
|
||||
SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
|
||||
EXPECT_TRUE(state.active_tree_needs_first_draw());
|
||||
EXPECT_TRUE(state.needs_redraw());
|
||||
} else {
|
||||
// Still need to require a draw, otherwise nothing will happen below.
|
||||
state.SetNeedsRedraw(true);
|
||||
}
|
||||
|
||||
// Expect to do nothing until BeginImplFrame deadline
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
state.OnBeginImplFrameDeadline();
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
|
||||
state.DidSubmitCompositorFrame();
|
||||
state.DidReceiveCompositorFrameAck();
|
||||
|
||||
// Should be synchronized, no draw needed, no action needed.
|
||||
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
|
||||
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
|
||||
EXPECT_FALSE(state.needs_redraw());
|
||||
|
||||
begin_main_frame_count +=
|
||||
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
|
||||
state.AdvanceTimeBy(base::Hertz(120));
|
||||
}
|
||||
|
||||
EXPECT_EQ(begin_main_frame_count, 5);
|
||||
}
|
||||
|
||||
TEST(SchedulerStateMachineTest, TestMainFrameThrottlingWithUrgentUpdates) {
|
||||
SchedulerSettings default_scheduler_settings;
|
||||
StateMachine state(default_scheduler_settings);
|
||||
SET_UP_STATE(state);
|
||||
|
||||
state.SetThrottleMainFrames(base::Hertz(60));
|
||||
state.AdvanceTimeBy(base::Seconds(1280)); // Start at an arbitrary point.
|
||||
|
||||
int begin_main_frame_count = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
state.SetNeedsBeginMainFrame(true);
|
||||
begin_main_frame_count +=
|
||||
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
|
||||
state.AdvanceTimeBy(base::Hertz(120));
|
||||
}
|
||||
// All the urgent updates result in main frames.
|
||||
EXPECT_EQ(begin_main_frame_count, 10);
|
||||
|
||||
begin_main_frame_count = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
state.SetNeedsBeginMainFrame(false);
|
||||
state.SetNeedsBeginMainFrame(true);
|
||||
begin_main_frame_count +=
|
||||
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
|
||||
state.AdvanceTimeBy(base::Hertz(120));
|
||||
}
|
||||
// Same when we get multiple requests in a frame, one urgent.
|
||||
EXPECT_EQ(begin_main_frame_count, 10);
|
||||
|
||||
begin_main_frame_count = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
bool urgent = i < 3;
|
||||
state.SetNeedsBeginMainFrame(urgent);
|
||||
begin_main_frame_count +=
|
||||
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
|
||||
state.AdvanceTimeBy(base::Hertz(120));
|
||||
}
|
||||
// One extra main frame, doesn't make all the subsequent ones urgent.
|
||||
EXPECT_EQ(begin_main_frame_count, 5 + 1);
|
||||
}
|
||||
|
||||
TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) {
|
||||
SchedulerSettings default_scheduler_settings;
|
||||
StateMachine state(default_scheduler_settings);
|
||||
|
@ -25,7 +25,7 @@ class FakeLayerTreeHostImplClient : public LayerTreeHostImplClient {
|
||||
void NotifyReadyToDraw() override;
|
||||
void SetNeedsRedrawOnImplThread() override {}
|
||||
void SetNeedsOneBeginImplFrameOnImplThread() override {}
|
||||
void SetNeedsCommitOnImplThread() override {}
|
||||
void SetNeedsCommitOnImplThread(bool urgent) override {}
|
||||
void SetNeedsPrepareTilesOnImplThread() override {}
|
||||
void SetVideoNeedsBeginFrames(bool needs_begin_frames) override {}
|
||||
void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override {}
|
||||
|
@ -31,7 +31,7 @@ class FakeProxy : public Proxy {
|
||||
void ReleaseLayerTreeFrameSink() override {}
|
||||
void SetShouldWarmUp() override {}
|
||||
void SetVisible(bool visible) override {}
|
||||
void SetNeedsAnimate() override {}
|
||||
void SetNeedsAnimate(bool urgent) override {}
|
||||
void SetNeedsUpdateLayers() override {}
|
||||
void SetNeedsCommit() override {}
|
||||
void SetNeedsRedraw(const gfx::Rect& damage_rect) override {}
|
||||
|
@ -130,7 +130,7 @@ class LayerTreeHostImplClient {
|
||||
// LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsOneBeginImplFrame().
|
||||
virtual void SetNeedsRedrawOnImplThread() = 0;
|
||||
virtual void SetNeedsOneBeginImplFrameOnImplThread() = 0;
|
||||
virtual void SetNeedsCommitOnImplThread() = 0;
|
||||
virtual void SetNeedsCommitOnImplThread(bool urgent = false) = 0;
|
||||
virtual void SetNeedsPrepareTilesOnImplThread() = 0;
|
||||
virtual void SetVideoNeedsBeginFrames(bool needs_begin_frames) = 0;
|
||||
virtual void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) = 0;
|
||||
|
@ -246,7 +246,9 @@ class LayerTreeHostImplTestBase : public testing::Test,
|
||||
void SetNeedsPrepareTilesOnImplThread() override {
|
||||
did_request_prepare_tiles_ = true;
|
||||
}
|
||||
void SetNeedsCommitOnImplThread() override { did_request_commit_ = true; }
|
||||
void SetNeedsCommitOnImplThread(bool urgent) override {
|
||||
did_request_commit_ = true;
|
||||
}
|
||||
void SetVideoNeedsBeginFrames(bool needs_begin_frames) override {}
|
||||
void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override {}
|
||||
bool IsInsideDraw() override { return false; }
|
||||
|
@ -47,7 +47,7 @@ class CC_EXPORT Proxy {
|
||||
virtual void SetVisible(bool visible) = 0;
|
||||
virtual void SetShouldWarmUp() = 0;
|
||||
|
||||
virtual void SetNeedsAnimate() = 0;
|
||||
virtual void SetNeedsAnimate(bool urgent = false) = 0;
|
||||
virtual void SetNeedsUpdateLayers() = 0;
|
||||
virtual void SetNeedsCommit() = 0;
|
||||
virtual void SetNeedsRedraw(const gfx::Rect& damage_rect) = 0;
|
||||
|
@ -239,8 +239,8 @@ void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
|
||||
SetNeedsRedrawOnImplThread();
|
||||
}
|
||||
|
||||
void ProxyImpl::SetNeedsCommitOnImpl() {
|
||||
SetNeedsCommitOnImplThread();
|
||||
void ProxyImpl::SetNeedsCommitOnImpl(bool urgent) {
|
||||
SetNeedsCommitOnImplThread(urgent);
|
||||
}
|
||||
|
||||
void ProxyImpl::SetTargetLocalSurfaceIdOnImpl(
|
||||
@ -413,7 +413,7 @@ void ProxyImpl::NotifyReadyToCommitOnImpl(
|
||||
// ApplyCompositorChanges. This means we are guaranteed to run another main
|
||||
// frame after FCP, which is good because there may be hover effects to apply.
|
||||
if (!scroll_and_viewport_changes_synced)
|
||||
scheduler_->SetNeedsBeginMainFrame();
|
||||
scheduler_->SetNeedsBeginMainFrame(false);
|
||||
}
|
||||
|
||||
void ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread() {
|
||||
@ -488,10 +488,10 @@ void ProxyImpl::SetNeedsPrepareTilesOnImplThread() {
|
||||
scheduler_->SetNeedsPrepareTiles();
|
||||
}
|
||||
|
||||
void ProxyImpl::SetNeedsCommitOnImplThread() {
|
||||
void ProxyImpl::SetNeedsCommitOnImplThread(bool urgent) {
|
||||
TRACE_EVENT0("cc", "ProxyImpl::SetNeedsCommitOnImplThread");
|
||||
DCHECK(IsImplThread());
|
||||
scheduler_->SetNeedsBeginMainFrame();
|
||||
scheduler_->SetNeedsBeginMainFrame(urgent);
|
||||
}
|
||||
|
||||
void ProxyImpl::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
|
||||
@ -622,7 +622,7 @@ void ProxyImpl::NotifyImageDecodeRequestFinished(int request_id,
|
||||
base::BindOnce(&ProxyMain::NotifyImageDecodeRequestFinished,
|
||||
proxy_main_weak_ptr_, request_id, decode_succeeded));
|
||||
} else {
|
||||
SetNeedsCommitOnImplThread();
|
||||
SetNeedsCommitOnImplThread(/* urgent= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
|
||||
void SetDeferBeginMainFrameFromMain(bool defer_begin_main_frame);
|
||||
void SetPauseRendering(bool pause_rendering);
|
||||
void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect);
|
||||
void SetNeedsCommitOnImpl();
|
||||
void SetNeedsCommitOnImpl(bool urgent);
|
||||
void SetTargetLocalSurfaceIdOnImpl(
|
||||
const viz::LocalSurfaceId& target_local_surface_id);
|
||||
void BeginMainFrameAbortedOnImpl(
|
||||
@ -115,7 +115,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
|
||||
void SetNeedsRedrawOnImplThread() override;
|
||||
void SetNeedsOneBeginImplFrameOnImplThread() override;
|
||||
void SetNeedsPrepareTilesOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread(bool urgent) override;
|
||||
void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
|
||||
void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override;
|
||||
bool IsInsideDraw() override;
|
||||
|
@ -195,6 +195,7 @@ void ProxyMain::BeginMainFrame(
|
||||
|
||||
final_pipeline_stage_ = max_requested_pipeline_stage_;
|
||||
max_requested_pipeline_stage_ = NO_PIPELINE_STAGE;
|
||||
has_sent_urgent_commit_request_ = false;
|
||||
|
||||
// If main frame updates and commits are deferred, skip the entire pipeline.
|
||||
if (defer_main_frame_update_ || pause_rendering_) {
|
||||
@ -563,9 +564,9 @@ void ProxyMain::SetShouldWarmUp() {
|
||||
base::Unretained(proxy_impl_.get())));
|
||||
}
|
||||
|
||||
void ProxyMain::SetNeedsAnimate() {
|
||||
void ProxyMain::SetNeedsAnimate(bool urgent) {
|
||||
DCHECK(IsMainThread());
|
||||
if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) {
|
||||
if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE, urgent)) {
|
||||
TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsAnimate",
|
||||
TRACE_EVENT_SCOPE_THREAD);
|
||||
}
|
||||
@ -579,7 +580,8 @@ void ProxyMain::SetNeedsUpdateLayers() {
|
||||
std::max(final_pipeline_stage_, UPDATE_LAYERS_PIPELINE_STAGE);
|
||||
return;
|
||||
}
|
||||
if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) {
|
||||
if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE,
|
||||
/* urgent = */ false)) {
|
||||
TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsUpdateLayers",
|
||||
TRACE_EVENT_SCOPE_THREAD);
|
||||
}
|
||||
@ -595,7 +597,8 @@ void ProxyMain::SetNeedsCommit() {
|
||||
std::max(final_pipeline_stage_, COMMIT_PIPELINE_STAGE);
|
||||
return;
|
||||
}
|
||||
if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) {
|
||||
if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE,
|
||||
/* urgent = */ false)) {
|
||||
TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsCommit",
|
||||
TRACE_EVENT_SCOPE_THREAD);
|
||||
}
|
||||
@ -864,18 +867,21 @@ void ProxyMain::RequestBeginMainFrameNotExpected(bool new_state) {
|
||||
}
|
||||
|
||||
bool ProxyMain::SendCommitRequestToImplThreadIfNeeded(
|
||||
CommitPipelineStage required_stage) {
|
||||
CommitPipelineStage required_stage,
|
||||
bool urgent) {
|
||||
DCHECK(IsMainThread());
|
||||
DCHECK_NE(NO_PIPELINE_STAGE, required_stage);
|
||||
bool already_posted = max_requested_pipeline_stage_ != NO_PIPELINE_STAGE;
|
||||
max_requested_pipeline_stage_ =
|
||||
std::max(max_requested_pipeline_stage_, required_stage);
|
||||
if (already_posted)
|
||||
if (already_posted && (!urgent || has_sent_urgent_commit_request_)) {
|
||||
return false;
|
||||
}
|
||||
ImplThreadTaskRunner()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ProxyImpl::SetNeedsCommitOnImpl,
|
||||
base::Unretained(proxy_impl_.get())));
|
||||
base::Unretained(proxy_impl_.get()), urgent));
|
||||
layer_tree_host_->OnCommitRequested();
|
||||
has_sent_urgent_commit_request_ |= urgent;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ class CC_EXPORT ProxyMain : public Proxy {
|
||||
LayerTreeFrameSink* layer_tree_frame_sink) override;
|
||||
void SetVisible(bool visible) override;
|
||||
void SetShouldWarmUp() override;
|
||||
void SetNeedsAnimate() override;
|
||||
void SetNeedsAnimate(bool urgent) override;
|
||||
void SetNeedsUpdateLayers() override;
|
||||
void SetNeedsCommit() override;
|
||||
void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
|
||||
@ -138,8 +138,8 @@ class CC_EXPORT ProxyMain : public Proxy {
|
||||
|
||||
// Returns |true| if the request was actually sent, |false| if one was
|
||||
// already outstanding.
|
||||
bool SendCommitRequestToImplThreadIfNeeded(
|
||||
CommitPipelineStage required_stage);
|
||||
bool SendCommitRequestToImplThreadIfNeeded(CommitPipelineStage required_stage,
|
||||
bool urgent);
|
||||
bool IsMainThread() const;
|
||||
bool IsImplThread() const;
|
||||
base::SingleThreadTaskRunner* ImplThreadTaskRunner();
|
||||
@ -170,6 +170,11 @@ class CC_EXPORT ProxyMain : public Proxy {
|
||||
// deferred.
|
||||
CommitPipelineStage deferred_final_pipeline_stage_;
|
||||
|
||||
// Commit requests are deduplicated, however if we requested a regular commit
|
||||
// request, then get an "urgent" request later, we should inform impl that the
|
||||
// request became urgent.
|
||||
bool has_sent_urgent_commit_request_ = false;
|
||||
|
||||
// Set when the Proxy is started using Proxy::Start() and reset when it is
|
||||
// stopped using Proxy::Stop().
|
||||
bool started_;
|
||||
|
@ -192,7 +192,7 @@ void SingleThreadProxy::SetLayerTreeFrameSink(
|
||||
}
|
||||
}
|
||||
|
||||
void SingleThreadProxy::SetNeedsAnimate() {
|
||||
void SingleThreadProxy::SetNeedsAnimate(bool urgent) {
|
||||
TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
|
||||
DCHECK(task_runner_provider_->IsMainThread());
|
||||
if (animate_requested_)
|
||||
@ -200,7 +200,7 @@ void SingleThreadProxy::SetNeedsAnimate() {
|
||||
animate_requested_ = true;
|
||||
DebugScopedSetImplThread impl(task_runner_provider_);
|
||||
if (scheduler_on_impl_thread_)
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame(urgent);
|
||||
layer_tree_host_->OnCommitRequested();
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ void SingleThreadProxy::SetNeedsUpdateLayers() {
|
||||
if (!RequestedAnimatePending()) {
|
||||
DebugScopedSetImplThread impl(task_runner_provider_);
|
||||
if (scheduler_on_impl_thread_)
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame(/* urgent = */ false);
|
||||
}
|
||||
update_layers_requested_ = true;
|
||||
}
|
||||
@ -305,7 +305,7 @@ void SingleThreadProxy::SetNeedsCommit() {
|
||||
commit_requested_ = true;
|
||||
DebugScopedSetImplThread impl(task_runner_provider_);
|
||||
if (scheduler_on_impl_thread_)
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame(/* urgent = */ false);
|
||||
}
|
||||
|
||||
void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
|
||||
@ -537,12 +537,12 @@ void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
|
||||
scheduler_on_impl_thread_->SetNeedsPrepareTiles();
|
||||
}
|
||||
|
||||
void SingleThreadProxy::SetNeedsCommitOnImplThread() {
|
||||
void SingleThreadProxy::SetNeedsCommitOnImplThread(bool urgent) {
|
||||
DCHECK(!task_runner_provider_->HasImplThread() ||
|
||||
task_runner_provider_->IsImplThread());
|
||||
single_thread_client_->ScheduleAnimationForWebTests();
|
||||
if (scheduler_on_impl_thread_)
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
|
||||
scheduler_on_impl_thread_->SetNeedsBeginMainFrame(urgent);
|
||||
commit_requested_ = true;
|
||||
}
|
||||
|
||||
@ -667,7 +667,7 @@ void SingleThreadProxy::NotifyImageDecodeRequestFinished(
|
||||
DebugScopedSetMainThread main_thread(task_runner_provider_);
|
||||
IssueImageDecodeFinishedCallbacks();
|
||||
} else {
|
||||
SetNeedsCommitOnImplThread();
|
||||
SetNeedsCommitOnImplThread(/* urgent = */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
|
||||
void ReleaseLayerTreeFrameSink() override;
|
||||
void SetVisible(bool visible) override;
|
||||
void SetShouldWarmUp() override;
|
||||
void SetNeedsAnimate() override;
|
||||
void SetNeedsAnimate(bool urgent) override;
|
||||
void SetNeedsUpdateLayers() override;
|
||||
void SetNeedsCommit() override;
|
||||
void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
|
||||
@ -131,7 +131,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
|
||||
void SetNeedsRedrawOnImplThread() override;
|
||||
void SetNeedsOneBeginImplFrameOnImplThread() override;
|
||||
void SetNeedsPrepareTilesOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread(bool urgent) override;
|
||||
void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
|
||||
void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override {}
|
||||
bool IsInsideDraw() override;
|
||||
|
@ -894,7 +894,7 @@ void LayerContextImpl::SetNeedsPrepareTilesOnImplThread() {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void LayerContextImpl::SetNeedsCommitOnImplThread() {
|
||||
void LayerContextImpl::SetNeedsCommitOnImplThread(bool urgent) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class LayerContextImpl : public cc::LayerTreeHostImplClient,
|
||||
void SetNeedsRedrawOnImplThread() override;
|
||||
void SetNeedsOneBeginImplFrameOnImplThread() override;
|
||||
void SetNeedsPrepareTilesOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread() override;
|
||||
void SetNeedsCommitOnImplThread(bool urgent) override;
|
||||
void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
|
||||
void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override;
|
||||
bool IsInsideDraw() override;
|
||||
|
Reference in New Issue
Block a user