| // Copyright 2026 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/compositor/external_begin_frame_adapter.h" |
| |
| #include "base/atomic_sequence_num.h" |
| #include "base/functional/bind.h" |
| #include "base/logging.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/trace_event/trace_event.h" |
| |
| namespace ui { |
| |
| // static |
| uint64_t ExternalBeginFrameAdapter::AllocateSourceId() { |
| // Start at 1 to avoid colliding with the default original_source_id_ (0) |
| // in ExternalBeginFrameSourceMojo. |
| static base::AtomicSequenceNumber counter; |
| return counter.GetNext() + 1; |
| } |
| |
| ExternalBeginFrameAdapter::ExternalBeginFrameAdapter( |
| Compositor* compositor, |
| BeginFrameSourceExtension* source) |
| : compositor_(compositor), source_(source) { |
| CHECK(compositor_); |
| CHECK(source_); |
| source_->SetDelegate(this); |
| } |
| |
| ExternalBeginFrameAdapter::~ExternalBeginFrameAdapter() { |
| source_->SetDelegate(nullptr); |
| } |
| |
| void ExternalBeginFrameAdapter::OnBeginFrame( |
| base::TimeTicks frame_time, |
| base::TimeTicks deadline, |
| base::TimeDelta interval, |
| base::OnceCallback<void(bool has_damage)> ack_callback) { |
| viz::BeginFrameArgs args = args_generator_.GenerateBeginFrameArgs( |
| source_id_, frame_time, deadline, interval, interval); |
| |
| TRACE_EVENT2("viz", "ExternalBeginFrameAdapter::OnBeginFrame", "frame_time", |
| frame_time, "sequence_number", args.frame_id.sequence_number); |
| |
| compositor_->IssueExternalBeginFrame( |
| args, |
| base::BindOnce(&ExternalBeginFrameAdapter::OnBeginFrameAck, |
| weak_factory_.GetWeakPtr(), std::move(ack_callback))); |
| } |
| |
| void ExternalBeginFrameAdapter::OnVSyncIntervalChanged( |
| base::TimeTicks timebase, |
| base::TimeDelta interval) { |
| TRACE_EVENT1("viz", "ExternalBeginFrameAdapter::OnVSyncIntervalChanged", |
| "interval_us", interval.InMicroseconds()); |
| compositor_->SetDisplayVSyncParameters(timebase, interval); |
| } |
| |
| mojo::PendingAssociatedRemote<viz::mojom::ExternalBeginFrameControllerClient> |
| ExternalBeginFrameAdapter::CreateExternalBeginFrameControllerClient() { |
| TRACE_EVENT0("ui", "ExternalBeginFrameAdapter::CreateClient"); |
| DVLOG(1) << "ExternalBeginFrameAdapter client bound"; |
| receivers_.Clear(); |
| source_->Reset(); |
| |
| mojo::PendingAssociatedRemote<viz::mojom::ExternalBeginFrameControllerClient> |
| remote; |
| receivers_.Add(this, remote.InitWithNewEndpointAndPassReceiver()); |
| |
| // The first frame will be buffered by Compositor::IssueExternalBeginFrame |
| // until the remote is bound in SetExternalBeginFrameController. |
| source_->SetNeedsBeginFrame(true); |
| |
| return remote; |
| } |
| |
| void ExternalBeginFrameAdapter::SetNeedsBeginFrame(bool needs_begin_frames) { |
| source_->SetNeedsBeginFrame(needs_begin_frames); |
| } |
| |
| void ExternalBeginFrameAdapter::SetPreferredInterval(base::TimeDelta interval) { |
| source_->SetPreferredInterval(interval); |
| } |
| |
| void ExternalBeginFrameAdapter::NeedsBeginFrameWithId(int64_t display_id, |
| bool needs_begin_frames) { |
| SetNeedsBeginFrame(needs_begin_frames); |
| } |
| |
| void ExternalBeginFrameAdapter::OnBeginFrameAck( |
| base::OnceCallback<void(bool)> ack_callback, |
| const viz::BeginFrameAck& ack) { |
| std::move(ack_callback).Run(ack.has_damage); |
| } |
| |
| } // namespace ui |