| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "android_webview/browser/gfx/begin_frame_source_webview.h" |
| |
| #include "android_webview/browser_jni_headers/RootBeginFrameSourceWebView_jni.h" |
| #include "base/auto_reset.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/no_destructor.h" |
| #include "base/trace_event/trace_event.h" |
| #include "components/power_scheduler/power_mode.h" |
| #include "components/power_scheduler/power_mode_arbiter.h" |
| #include "components/power_scheduler/power_mode_voter.h" |
| |
| namespace android_webview { |
| |
| class BeginFrameSourceWebView::BeginFrameObserver |
| : public viz::BeginFrameObserver { |
| public: |
| BeginFrameObserver(BeginFrameSourceWebView* owner) : owner_(owner) {} |
| |
| void OnBeginFrame(const viz::BeginFrameArgs& args) override { |
| last_used_begin_frame_args_ = args; |
| owner_->SendBeginFrame(args); |
| } |
| |
| const viz::BeginFrameArgs& LastUsedBeginFrameArgs() const override { |
| return last_used_begin_frame_args_; |
| } |
| |
| void OnBeginFrameSourcePausedChanged(bool paused) override { |
| owner_->OnSetBeginFrameSourcePaused(paused); |
| } |
| |
| bool WantsAnimateOnlyBeginFrames() const override { return true; } |
| |
| private: |
| const raw_ptr<BeginFrameSourceWebView> owner_; |
| viz::BeginFrameArgs last_used_begin_frame_args_; |
| }; |
| |
| BeginFrameSourceWebView::BeginFrameSourceClient::BeginFrameSourceClient( |
| android_webview::BeginFrameSourceWebView* owner) |
| : owner_(owner) {} |
| |
| BeginFrameSourceWebView::BeginFrameSourceClient::~BeginFrameSourceClient() = |
| default; |
| void BeginFrameSourceWebView::BeginFrameSourceClient::OnNeedsBeginFrames( |
| bool needs_begin_frames) { |
| owner_->OnNeedsBeginFrames(needs_begin_frames); |
| } |
| |
| BeginFrameSourceWebView::BeginFrameSourceWebView() |
| : ExternalBeginFrameSource(&bfs_client_), |
| bfs_client_(this), |
| parent_observer_(std::make_unique<BeginFrameObserver>(this)), |
| animation_power_mode_voter_( |
| power_scheduler::PowerModeArbiter::GetInstance()->NewVoter( |
| "PowerModeVoter.Animation")) { |
| OnSetBeginFrameSourcePaused(true); |
| } |
| |
| BeginFrameSourceWebView::~BeginFrameSourceWebView() { |
| if (observed_begin_frame_source_ && !observers_.empty()) |
| observed_begin_frame_source_->RemoveObserver(parent_observer_.get()); |
| } |
| |
| void BeginFrameSourceWebView::SetParentSource(BeginFrameSourceWebView* parent) { |
| parent_ = parent; |
| ObserveBeginFrameSource(parent); |
| } |
| |
| void BeginFrameSourceWebView::ObserveBeginFrameSource( |
| viz::BeginFrameSource* begin_frame_source) { |
| if (observed_begin_frame_source_ == begin_frame_source) |
| return; |
| |
| if (observed_begin_frame_source_ && !observers_.empty()) |
| observed_begin_frame_source_->RemoveObserver(parent_observer_.get()); |
| |
| observed_begin_frame_source_ = begin_frame_source; |
| |
| if (observed_begin_frame_source_) { |
| if (!observers_.empty()) |
| observed_begin_frame_source_->AddObserver(parent_observer_.get()); |
| } else { |
| OnSetBeginFrameSourcePaused(true); |
| }; |
| } |
| |
| void BeginFrameSourceWebView::OnNeedsBeginFrames(bool needs_begin_frames) { |
| if (needs_begin_frames) { |
| TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this); |
| animation_power_mode_voter_->VoteFor( |
| power_scheduler::PowerMode::kAnimation); |
| if (observed_begin_frame_source_) |
| observed_begin_frame_source_->AddObserver(parent_observer_.get()); |
| } else { |
| TRACE_EVENT_NESTABLE_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this); |
| animation_power_mode_voter_->ResetVoteAfterTimeout( |
| power_scheduler::PowerModeVoter::kAnimationTimeout); |
| if (observed_begin_frame_source_) |
| observed_begin_frame_source_->RemoveObserver(parent_observer_.get()); |
| } |
| } |
| |
| void BeginFrameSourceWebView::SendBeginFrame(const viz::BeginFrameArgs& args) { |
| DCHECK(!inside_begin_frame_); |
| base::AutoReset<bool> inside_bf(&inside_begin_frame_, true); |
| OnBeginFrame(args); |
| AfterBeginFrame(); |
| } |
| |
| void BeginFrameSourceWebView::AddBeginFrameCompletionCallback( |
| base::OnceClosure callback) { |
| DCHECK(parent_); |
| DCHECK(inside_begin_frame_); |
| parent_->AddBeginFrameCompletionCallback(std::move(callback)); |
| } |
| |
| const viz::BeginFrameArgs& |
| BeginFrameSourceWebView::LastDispatchedBeginFrameArgs() { |
| return parent_observer_->LastUsedBeginFrameArgs(); |
| } |
| |
| // static |
| RootBeginFrameSourceWebView* RootBeginFrameSourceWebView::GetInstance() { |
| static base::NoDestructor<RootBeginFrameSourceWebView> instance; |
| return instance.get(); |
| } |
| |
| RootBeginFrameSourceWebView::RootBeginFrameSourceWebView() |
| : begin_frame_source_(kNotRestartableId, |
| 60.0f, |
| /*requires_align_with_java=*/true), |
| j_object_(Java_RootBeginFrameSourceWebView_Constructor( |
| base::android::AttachCurrentThread(), |
| reinterpret_cast<jlong>(this))) { |
| ObserveBeginFrameSource(&begin_frame_source_); |
| } |
| |
| RootBeginFrameSourceWebView::~RootBeginFrameSourceWebView() = default; |
| |
| void RootBeginFrameSourceWebView::OnUpdateRefreshRate( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jobject>& obj, |
| float refresh_rate) { |
| begin_frame_source_.UpdateRefreshRate(refresh_rate); |
| } |
| |
| void RootBeginFrameSourceWebView::AfterBeginFrame() { |
| // ScopedClosureRunner runs callback in the destructor unless it's cancelled. |
| // So this will run all callbacks scheduled to run after BeginFrame completed. |
| after_begin_frame_callbacks_.clear(); |
| } |
| |
| void RootBeginFrameSourceWebView::AddBeginFrameCompletionCallback( |
| base::OnceClosure callback) { |
| DCHECK(inside_begin_frame()); |
| after_begin_frame_callbacks_.emplace_back(std::move(callback)); |
| } |
| |
| } // namespace android_webview |