[go: nahoru, domu]

cc: Introduce LayerContext

This introduces new LayerContext and LayerContextClient abstractions in
cc as well as their corresponding mojom interfaces in Viz.  These types
sit between a client-side LayerTreeHost and a corresponding
LayerTreeHostImpl which may reside in another process. They will be used
to experiment with GPU-side layer trees.

This CL only introduces minimal boilerplate and plumbing for a client to
construct a new client-side VizLayerContext over an established
CompositorFrameSink endpoint, to control a GPU-side LayerTreeHost owned
by that sink within Viz.

Test coverage and actual frame production from a LayerContext are done
in a follow-up CL.

Bug: 1431762
Change-Id: I86e9150aa034fe77300036816c8e2c5ae3999c55
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4418567
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Auto-Submit: Ken Rockot <rockot@google.com>
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1130132}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 05e11fe..d59e047 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -366,6 +366,8 @@
     "trees/latency_info_swap_promise.h",
     "trees/latency_info_swap_promise_monitor.cc",
     "trees/latency_info_swap_promise_monitor.h",
+    "trees/layer_context.h",
+    "trees/layer_context_client.h",
     "trees/layer_tree_frame_sink.cc",
     "trees/layer_tree_frame_sink.h",
     "trees/layer_tree_frame_sink_client.h",
@@ -381,6 +383,8 @@
     "trees/layer_tree_mutator.h",
     "trees/layer_tree_settings.cc",
     "trees/layer_tree_settings.h",
+    "trees/local_layer_context.cc",
+    "trees/local_layer_context.h",
     "trees/managed_memory_policy.cc",
     "trees/managed_memory_policy.h",
     "trees/mobile_optimized_viewport_util.cc",
diff --git a/cc/mojo_embedder/BUILD.gn b/cc/mojo_embedder/BUILD.gn
index 32c65d2..152c647 100644
--- a/cc/mojo_embedder/BUILD.gn
+++ b/cc/mojo_embedder/BUILD.gn
@@ -9,6 +9,8 @@
   sources = [
     "async_layer_tree_frame_sink.cc",
     "async_layer_tree_frame_sink.h",
+    "viz_layer_context.cc",
+    "viz_layer_context.h",
   ]
 
   defines = [ "CC_MOJO_EMBEDDER_IMPLEMENTATION" ]
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc
new file mode 100644
index 0000000..8b74d2cab
--- /dev/null
+++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -0,0 +1,49 @@
+// Copyright 2023 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/mojo_embedder/viz_layer_context.h"
+
+#include <utility>
+
+#include "base/check.h"
+#include "cc/trees/layer_context_client.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
+
+namespace cc::mojo_embedder {
+
+VizLayerContext::VizLayerContext(viz::mojom::CompositorFrameSink& frame_sink,
+                                 cc::LayerContextClient* client)
+    : client_(client) {
+  CHECK(client_);
+  auto context = viz::mojom::PendingLayerContext::New();
+  context->receiver = service_.BindNewEndpointAndPassReceiver();
+  context->client = client_receiver_.BindNewEndpointAndPassRemote();
+  frame_sink.BindLayerContext(std::move(context));
+}
+
+VizLayerContext::~VizLayerContext() = default;
+
+void VizLayerContext::SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) {
+  service_->SetTargetLocalSurfaceId(id);
+}
+
+void VizLayerContext::SetVisible(bool visible) {
+  service_->SetVisible(visible);
+}
+
+void VizLayerContext::Commit(const CommitState& state) {
+  // TODO(https://crbug.com/1431762): Push actual commit data. For now we only
+  // update basic parameters required for any LayerTreeHost drawing.
+  auto update = viz::mojom::LayerTreeUpdate::New();
+  update->device_viewport = state.device_viewport_rect;
+  update->device_scale_factor = state.device_scale_factor;
+  update->local_surface_id_from_parent = state.local_surface_id_from_parent;
+  service_->Commit(std::move(update));
+}
+
+void VizLayerContext::OnRequestCommitForFrame(const viz::BeginFrameArgs& args) {
+  client_->OnRequestCommitForFrame(args);
+}
+
+}  // namespace cc::mojo_embedder
diff --git a/cc/mojo_embedder/viz_layer_context.h b/cc/mojo_embedder/viz_layer_context.h
new file mode 100644
index 0000000..dd24603
--- /dev/null
+++ b/cc/mojo_embedder/viz_layer_context.h
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_
+#define CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_
+
+#include "base/memory/raw_ptr.h"
+#include "cc/mojo_embedder/mojo_embedder_export.h"
+#include "cc/trees/layer_context.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
+
+namespace cc {
+class LayerContextClient;
+}  // namespace cc
+
+namespace cc::mojo_embedder {
+
+// A client-side implementation of LayerContext which runs over a Mojo
+// connection to a GPU-side LayerContext backend within Viz.
+class CC_MOJO_EMBEDDER_EXPORT VizLayerContext
+    : public LayerContext,
+      public viz::mojom::LayerContextClient {
+ public:
+  // Constructs a VizLayerContext which submits content on behalf of
+  // `frame_sink`. `client` must outlive this object.
+  VizLayerContext(viz::mojom::CompositorFrameSink& frame_sink,
+                  cc::LayerContextClient* client);
+  ~VizLayerContext() override;
+
+  // LayerContext:
+  void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) override;
+  void SetVisible(bool visible) override;
+  void Commit(const CommitState& state) override;
+
+  // viz::mojom::LayerContextClient:
+  void OnRequestCommitForFrame(const viz::BeginFrameArgs& args) override;
+
+ private:
+  raw_ptr<cc::LayerContextClient> client_;
+  mojo::AssociatedReceiver<viz::mojom::LayerContextClient> client_receiver_{
+      this};
+  mojo::AssociatedRemote<viz::mojom::LayerContext> service_;
+};
+
+}  // namespace cc::mojo_embedder
+
+#endif  // CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_
diff --git a/cc/slim/test_frame_sink_impl.cc b/cc/slim/test_frame_sink_impl.cc
index 84f9e7a7..af27c9d 100644
--- a/cc/slim/test_frame_sink_impl.cc
+++ b/cc/slim/test_frame_sink_impl.cc
@@ -17,6 +17,7 @@
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 
 namespace cc::slim {
 
@@ -49,6 +50,7 @@
   void DidDeleteSharedBitmap(const gpu::Mailbox& id) override {}
   void InitializeCompositorFrameSinkType(
       viz::mojom::CompositorFrameSinkType type) override {}
+  void BindLayerContext(viz::mojom::PendingLayerContextPtr context) override {}
 #if BUILDFLAG(IS_ANDROID)
   void SetThreadIds(const std::vector<int32_t>& thread_ids) override {}
 #endif
diff --git a/cc/trees/layer_context.h b/cc/trees/layer_context.h
new file mode 100644
index 0000000..95726a1
--- /dev/null
+++ b/cc/trees/layer_context.h
@@ -0,0 +1,35 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_LAYER_CONTEXT_H_
+#define CC_TREES_LAYER_CONTEXT_H_
+
+#include "cc/cc_export.h"
+#include "cc/trees/commit_state.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+
+namespace cc {
+
+// LayerContext provides an opaque interface through which a LayerTreeHost can
+// control a backing LayerTreeHostImpl, potentially on another thread or in
+// another process.
+class CC_EXPORT LayerContext {
+ public:
+  virtual ~LayerContext() = default;
+
+  // Indicates that a new LocalSurfaceId has been set for the frame sink hosting
+  // this tree.
+  virtual void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) = 0;
+
+  // Globally controls the visibility of layers within the tree.
+  virtual void SetVisible(bool visible) = 0;
+
+  // Flushes pending updates to the backing LayerTreeHostImpl. `state`
+  // represents the pending CommitState for the client-side LayerTreeHost.
+  virtual void Commit(const CommitState& state) = 0;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_LAYER_CONTEXT_H_
diff --git a/cc/trees/layer_context_client.h b/cc/trees/layer_context_client.h
new file mode 100644
index 0000000..2514c245
--- /dev/null
+++ b/cc/trees/layer_context_client.h
@@ -0,0 +1,27 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_LAYER_CONTEXT_CLIENT_H_
+#define CC_TREES_LAYER_CONTEXT_CLIENT_H_
+
+#include "cc/cc_export.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+
+namespace cc {
+
+// Interface used by LayerContext to push requests to its corresponding
+// client-side LayerTreeHost.
+class CC_EXPORT LayerContextClient {
+ public:
+  virtual ~LayerContextClient() = default;
+
+  // Indicates that the compositor will produce a new display frame soon and
+  // that the client should commit a new layer tree ASAP. `args` correspond to
+  // the impending display frame that the compositor wants to produce.
+  virtual void OnRequestCommitForFrame(const viz::BeginFrameArgs& args) = 0;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_LAYER_CONTEXT_CLIENT_H_
diff --git a/cc/trees/local_layer_context.cc b/cc/trees/local_layer_context.cc
new file mode 100644
index 0000000..0238c079
--- /dev/null
+++ b/cc/trees/local_layer_context.cc
@@ -0,0 +1,151 @@
+// Copyright 2023 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/trees/local_layer_context.h"
+
+#include <memory>
+
+#include "base/task/single_thread_task_runner.h"
+#include "cc/raster/categorized_worker_pool.h"
+#include "cc/trees/commit_state.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_settings.h"
+
+namespace cc {
+
+namespace {
+
+LayerListSettings CreateSettings() {
+  LayerListSettings settings;
+  settings.commit_to_active_tree = true;
+  return settings;
+}
+
+LayerTreeHost::InitParams CreateInitParams(LocalLayerContext& context,
+                                           const LayerListSettings& settings,
+                                           MutatorHost* mutator_host) {
+  LayerTreeHost::InitParams params;
+  params.client = &context;
+  params.settings = &settings;
+  params.task_graph_runner = CategorizedWorkerPool::GetOrCreate();
+  params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
+  params.mutator_host = mutator_host;
+  return params;
+}
+
+}  // namespace
+
+LocalLayerContext::LocalLayerContext(MutatorHost* mutator_host)
+    : mutator_host_(mutator_host),
+      layer_list_settings_(CreateSettings()),
+      host_(LayerTreeHost::CreateSingleThreaded(
+          this,
+          CreateInitParams(*this, layer_list_settings_, mutator_host_))) {}
+
+LocalLayerContext::~LocalLayerContext() = default;
+
+void LocalLayerContext::SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) {
+  host_->SetTargetLocalSurfaceId(id);
+}
+
+void LocalLayerContext::SetVisible(bool visible) {
+  host_->SetVisible(visible);
+}
+
+void LocalLayerContext::Commit(const CommitState& state) {
+  // TODO(https://crbug.com/1431762): Actually update the tree contents.
+  host_->SetViewportRectAndScale(state.device_viewport_rect,
+                                 state.device_scale_factor,
+                                 state.local_surface_id_from_parent);
+}
+
+void LocalLayerContext::WillBeginMainFrame() {}
+
+void LocalLayerContext::DidBeginMainFrame() {}
+
+void LocalLayerContext::WillUpdateLayers() {}
+
+void LocalLayerContext::DidUpdateLayers() {}
+
+void LocalLayerContext::BeginMainFrame(const viz::BeginFrameArgs& args) {}
+
+void LocalLayerContext::OnDeferMainFrameUpdatesChanged(bool) {}
+
+void LocalLayerContext::OnDeferCommitsChanged(
+    bool defer_status,
+    PaintHoldingReason reason,
+    absl::optional<PaintHoldingCommitTrigger> trigger) {}
+
+void LocalLayerContext::OnCommitRequested() {}
+
+void LocalLayerContext::BeginMainFrameNotExpectedSoon() {}
+
+void LocalLayerContext::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {}
+
+void LocalLayerContext::UpdateLayerTreeHost() {}
+
+void LocalLayerContext::ApplyViewportChanges(
+    const ApplyViewportChangesArgs& args) {}
+
+void LocalLayerContext::UpdateCompositorScrollState(
+    const CompositorCommitData& commit_data) {}
+
+void LocalLayerContext::RequestNewLayerTreeFrameSink() {}
+
+void LocalLayerContext::DidInitializeLayerTreeFrameSink() {}
+
+void LocalLayerContext::DidFailToInitializeLayerTreeFrameSink() {}
+
+void LocalLayerContext::WillCommit(const CommitState&) {}
+
+void LocalLayerContext::DidCommit(base::TimeTicks commit_start_time,
+                                  base::TimeTicks commit_finish_time) {}
+
+void LocalLayerContext::DidCommitAndDrawFrame() {}
+
+void LocalLayerContext::DidReceiveCompositorFrameAck() {}
+
+void LocalLayerContext::DidCompletePageScaleAnimation() {}
+
+void LocalLayerContext::DidPresentCompositorFrame(
+    uint32_t frame_token,
+    const gfx::PresentationFeedback& feedback) {}
+
+void LocalLayerContext::RecordStartOfFrameMetrics() {}
+
+void LocalLayerContext::RecordEndOfFrameMetrics(
+    base::TimeTicks frame_begin_time,
+    ActiveFrameSequenceTrackers trackers) {}
+
+std::unique_ptr<BeginMainFrameMetrics>
+LocalLayerContext::GetBeginMainFrameMetrics() {
+  return nullptr;
+}
+
+std::unique_ptr<WebVitalMetrics> LocalLayerContext::GetWebVitalMetrics() {
+  return nullptr;
+}
+
+void LocalLayerContext::NotifyThroughputTrackerResults(
+    CustomTrackerResults results) {}
+
+void LocalLayerContext::DidObserveFirstScrollDelay(
+    base::TimeDelta first_scroll_delay,
+    base::TimeTicks first_scroll_timestamp) {}
+
+void LocalLayerContext::RunPaintBenchmark(int repeat_count,
+                                          PaintBenchmarkResult& result) {}
+
+void LocalLayerContext::ScheduleAnimationForWebTests() {}
+
+void LocalLayerContext::FrameIntervalUpdated(base::TimeDelta interval) {}
+
+void LocalLayerContext::DidSubmitCompositorFrame() {}
+
+void LocalLayerContext::DidLoseLayerTreeFrameSink() {}
+
+void LocalLayerContext::FrameSinksToThrottleUpdated(
+    const base::flat_set<viz::FrameSinkId>& ids) {}
+
+}  // namespace cc
diff --git a/cc/trees/local_layer_context.h b/cc/trees/local_layer_context.h
new file mode 100644
index 0000000..106a711
--- /dev/null
+++ b/cc/trees/local_layer_context.h
@@ -0,0 +1,98 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_LOCAL_LAYER_CONTEXT_H_
+#define CC_TREES_LOCAL_LAYER_CONTEXT_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "cc/cc_export.h"
+#include "cc/trees/layer_context.h"
+#include "cc/trees/layer_tree_host_client.h"
+#include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "cc/trees/layer_tree_settings.h"
+
+namespace cc {
+
+class LayerTreeHost;
+class MutatorHost;
+
+// LocalLayerContext owns and manages a LayerTreeHostImpl to be controlled
+// indirectly by a client's corresponding LayerTreeHost.
+class CC_EXPORT LocalLayerContext : public LayerContext,
+                                    public LayerTreeHostClient,
+                                    public LayerTreeHostSingleThreadClient {
+ public:
+  explicit LocalLayerContext(MutatorHost* mutator_host);
+  ~LocalLayerContext() override;
+
+  // LayerContext:
+  void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) override;
+  void SetVisible(bool visible) override;
+  void Commit(const CommitState& state) override;
+
+  // LayerTreeHostClient:
+  void WillBeginMainFrame() override;
+  void DidBeginMainFrame() override;
+  void WillUpdateLayers() override;
+  void DidUpdateLayers() override;
+  void BeginMainFrame(const viz::BeginFrameArgs& args) override;
+  void OnDeferMainFrameUpdatesChanged(bool) override;
+  void OnDeferCommitsChanged(
+      bool defer_status,
+      PaintHoldingReason reason,
+      absl::optional<PaintHoldingCommitTrigger> trigger) override;
+  void OnCommitRequested() override;
+  void BeginMainFrameNotExpectedSoon() override;
+  void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override;
+  void UpdateLayerTreeHost() override;
+  void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override;
+  void UpdateCompositorScrollState(
+      const CompositorCommitData& commit_data) override;
+  void RequestNewLayerTreeFrameSink() override;
+  void DidInitializeLayerTreeFrameSink() override;
+  void DidFailToInitializeLayerTreeFrameSink() override;
+  void WillCommit(const CommitState&) override;
+  void DidCommit(base::TimeTicks commit_start_time,
+                 base::TimeTicks commit_finish_time) override;
+  void DidCommitAndDrawFrame() override;
+  void DidReceiveCompositorFrameAck() override;
+  void DidCompletePageScaleAnimation() override;
+  void DidPresentCompositorFrame(
+      uint32_t frame_token,
+      const gfx::PresentationFeedback& feedback) override;
+  void RecordStartOfFrameMetrics() override;
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time,
+                               ActiveFrameSequenceTrackers trackers) override;
+  std::unique_ptr<BeginMainFrameMetrics> GetBeginMainFrameMetrics() override;
+  std::unique_ptr<WebVitalMetrics> GetWebVitalMetrics() override;
+  void NotifyThroughputTrackerResults(CustomTrackerResults results) override;
+  void DidObserveFirstScrollDelay(
+      base::TimeDelta first_scroll_delay,
+      base::TimeTicks first_scroll_timestamp) override;
+  void RunPaintBenchmark(int repeat_count,
+                         PaintBenchmarkResult& result) override;
+
+  // LayerTreeHostSingleThreadClient:
+  void ScheduleAnimationForWebTests() override;
+  void FrameIntervalUpdated(base::TimeDelta interval) override;
+  void DidSubmitCompositorFrame() override;
+  void DidLoseLayerTreeFrameSink() override;
+  void FrameSinksToThrottleUpdated(
+      const base::flat_set<viz::FrameSinkId>& ids) override;
+
+ private:
+  const raw_ptr<MutatorHost> mutator_host_;
+
+  // The concrete LayerTreeHost which the client is controlling.
+  // TODO(https://crbug.com/1431762): Own and manage a LayerTreeHostImpl
+  // directly instead of proxying through a single-threaded LayerTreeHost.
+  const LayerListSettings layer_list_settings_;
+  std::unique_ptr<LayerTreeHost> host_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_LOCAL_LAYER_CONTEXT_H_
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
index f26edd6..43a93ea 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
@@ -27,6 +27,7 @@
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -232,6 +233,7 @@
       SubmitCompositorFrameSyncCallback callback) override {}
   void InitializeCompositorFrameSinkType(
       viz::mojom::CompositorFrameSinkType type) override {}
+  void BindLayerContext(viz::mojom::PendingLayerContextPtr context) override {}
   void SetThreadIds(const std::vector<int32_t>& thread_ids) override {}
 
   // mojom::ExternalBeginFrameController implementation.
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 395917c..96fe556 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -189,6 +189,8 @@
     "hit_test/hit_test_aggregator_delegate.h",
     "hit_test/hit_test_manager.cc",
     "hit_test/hit_test_manager.h",
+    "layers/layer_context_impl.cc",
+    "layers/layer_context_impl.h",
     "performance_hint/hint_session.cc",
     "performance_hint/hint_session.h",
     "performance_hint/utils.cc",
@@ -246,6 +248,7 @@
     "//media",
     "//media/capture:capture_lib",
     "//media/mojo/services",
+    "//services/metrics/public/mojom",
     "//services/tracing/public/cpp:cpp",
     "//services/viz/privileged/mojom",
     "//skia",
@@ -257,6 +260,8 @@
 
   public_deps = [
     "//base",
+    "//cc",
+    "//cc/animation",
     "//cc/debug",
     "//components/viz/common",
     "//gpu/command_buffer/service:gles2",
@@ -264,6 +269,7 @@
     "//gpu/vulkan:buildflags",
     "//media/gpu/ipc/service",
     "//media/mojo/services",
+    "//services/metrics/public/cpp:metrics_cpp",
     "//services/viz/privileged/mojom/compositing",
     "//services/viz/privileged/mojom/gl",
     "//services/viz/public/mojom",
diff --git a/components/viz/service/frame_sinks/DEPS b/components/viz/service/frame_sinks/DEPS
index b62ceac..163224a 100644
--- a/components/viz/service/frame_sinks/DEPS
+++ b/components/viz/service/frame_sinks/DEPS
@@ -6,6 +6,7 @@
   "+components/viz/service/display",
   "+components/viz/service/display_embedder",
   "+components/viz/service/hit_test",
+  "+components/viz/service/layers",
   "+components/viz/service/performance_hint",
   "+components/viz/service/surfaces",
   "+components/viz/service/transitions",
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
index a9c7bb4..eeec1ba 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 #include "ui/gfx/overlay_transform.h"
 
 namespace viz {
@@ -199,6 +200,11 @@
   support_->InitializeCompositorFrameSinkType(type);
 }
 
+void CompositorFrameSinkImpl::BindLayerContext(
+    mojom::PendingLayerContextPtr context) {
+  support_->BindLayerContext(*context);
+}
+
 #if BUILDFLAG(IS_ANDROID)
 void CompositorFrameSinkImpl::SetThreadIds(
     const std::vector<int32_t>& thread_ids) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
index 90af1827..3df7c43 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -61,6 +61,7 @@
   void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
   void InitializeCompositorFrameSinkType(
       mojom::CompositorFrameSinkType type) override;
+  void BindLayerContext(mojom::PendingLayerContextPtr context) override;
 #if BUILDFLAG(IS_ANDROID)
   void SetThreadIds(const std::vector<int32_t>& thread_ids) override;
 #endif
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 966f54b..e55a674 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -459,6 +459,11 @@
   }
 }
 
+void CompositorFrameSinkSupport::BindLayerContext(
+    mojom::PendingLayerContext& context) {
+  layer_context_impl_ = std::make_unique<LayerContextImpl>(context);
+}
+
 void CompositorFrameSinkSupport::SetThreadIds(
     bool from_untrusted_client,
     base::flat_set<base::PlatformThreadId> unverified_thread_ids) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index c8350efc..b55a8d8 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -29,11 +29,13 @@
 #include "components/viz/service/frame_sinks/surface_resource_holder_client.h"
 #include "components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h"
 #include "components/viz/service/hit_test/hit_test_aggregator.h"
+#include "components/viz/service/layers/layer_context_impl.h"
 #include "components/viz/service/surfaces/frame_index_constants.h"
 #include "components/viz/service/surfaces/surface_client.h"
 #include "components/viz/service/transitions/surface_animation_manager.h"
 #include "components/viz/service/viz_service_export.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -41,6 +43,7 @@
 
 class FrameSinkManagerImpl;
 class LatestLocalSurfaceIdLookupDelegate;
+class LayerContextImpl;
 class Surface;
 class SurfaceManager;
 
@@ -132,6 +135,7 @@
   base::TimeDelta GetPreferredFrameInterval(
       mojom::CompositorFrameSinkType* type) const;
   void InitializeCompositorFrameSinkType(mojom::CompositorFrameSinkType type);
+  void BindLayerContext(mojom::PendingLayerContext& context);
   void SetThreadIds(
       bool from_untrusted_client,
       base::flat_set<base::PlatformThreadId> unverified_thread_ids);
@@ -455,6 +459,10 @@
   // Region capture bounds associated with the last surface that was aggregated.
   RegionCaptureBounds current_capture_bounds_;
 
+  // In LayerContext mode only, this is the Viz LayerContext implementation
+  // which owns the backend layer tree for this frame sink.
+  std::unique_ptr<LayerContextImpl> layer_context_impl_;
+
   base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_{this};
 };
 
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index b2dec27..0110919 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -25,6 +25,7 @@
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
 #include "components/viz/service/hit_test/hit_test_aggregator.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 #include "ui/gfx/geometry/skia_conversions.h"
 
 #if BUILDFLAG(IS_ANDROID)
@@ -493,6 +494,11 @@
   support_->InitializeCompositorFrameSinkType(type);
 }
 
+void RootCompositorFrameSinkImpl::BindLayerContext(
+    mojom::PendingLayerContextPtr context) {
+  support_->BindLayerContext(*context);
+}
+
 #if BUILDFLAG(IS_ANDROID)
 void RootCompositorFrameSinkImpl::SetThreadIds(
     const std::vector<int32_t>& thread_ids) {
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
index 559a8cc..c3c15f9c 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -121,6 +121,7 @@
       SubmitCompositorFrameSyncCallback callback) override;
   void InitializeCompositorFrameSinkType(
       mojom::CompositorFrameSinkType type) override;
+  void BindLayerContext(mojom::PendingLayerContextPtr context) override;
 #if BUILDFLAG(IS_ANDROID)
   void SetThreadIds(const std::vector<int32_t>& thread_ids) override;
 #endif
diff --git a/components/viz/service/layers/DEPS b/components/viz/service/layers/DEPS
new file mode 100644
index 0000000..27a6d9ae
--- /dev/null
+++ b/components/viz/service/layers/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+    "+components/viz/service/frame_sinks",
+    "+mojo/public",
+]
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc
new file mode 100644
index 0000000..5992805
--- /dev/null
+++ b/components/viz/service/layers/layer_context_impl.cc
@@ -0,0 +1,37 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/layers/layer_context_impl.h"
+
+#include <utility>
+
+#include "cc/trees/commit_state.h"
+#include "cc/trees/layer_tree_host.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+
+namespace viz {
+
+LayerContextImpl::LayerContextImpl(mojom::PendingLayerContext& context)
+    : receiver_(this, std::move(context.receiver)),
+      client_(std::move(context.client)) {}
+
+LayerContextImpl::~LayerContextImpl() = default;
+
+void LayerContextImpl::SetTargetLocalSurfaceId(const LocalSurfaceId& id) {
+  context_.SetTargetLocalSurfaceId(id);
+}
+
+void LayerContextImpl::SetVisible(bool visible) {
+  context_.SetVisible(visible);
+}
+
+void LayerContextImpl::Commit(mojom::LayerTreeUpdatePtr update) {
+  cc::CommitState state;
+  state.device_viewport_rect = update->device_viewport;
+  state.device_scale_factor = update->device_scale_factor;
+  state.local_surface_id_from_parent = update->local_surface_id_from_parent;
+  context_.Commit(state);
+}
+
+}  // namespace viz
diff --git a/components/viz/service/layers/layer_context_impl.h b/components/viz/service/layers/layer_context_impl.h
new file mode 100644
index 0000000..31b6cd4
--- /dev/null
+++ b/components/viz/service/layers/layer_context_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_
+
+#include <memory>
+
+#include "cc/animation/animation_host.h"
+#include "cc/trees/local_layer_context.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom.h"
+
+namespace viz {
+
+// Implements the Viz LayerContext API backed by a LocalLayerContext. This
+// provides the service backend for a client-side VizLayerContext.
+class LayerContextImpl : public mojom::LayerContext {
+ public:
+  // Constructs a new LayerContextImpl with client connection details given by
+  // `context`.
+  explicit LayerContextImpl(mojom::PendingLayerContext& context);
+  ~LayerContextImpl() override;
+
+ private:
+  // mojom::LayerContext:
+  void SetTargetLocalSurfaceId(const LocalSurfaceId& id) override;
+  void SetVisible(bool visible) override;
+  void Commit(mojom::LayerTreeUpdatePtr update) override;
+
+  const std::unique_ptr<cc::AnimationHost> animation_host_{
+      cc::AnimationHost::CreateMainInstance()};
+  cc::LocalLayerContext context_{animation_host_.get()};
+
+  mojo::AssociatedReceiver<mojom::LayerContext> receiver_;
+  mojo::AssociatedRemote<mojom::LayerContextClient> client_;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_
diff --git a/services/viz/public/mojom/BUILD.gn b/services/viz/public/mojom/BUILD.gn
index a4bc44b..17f0b9ab 100644
--- a/services/viz/public/mojom/BUILD.gn
+++ b/services/viz/public/mojom/BUILD.gn
@@ -24,6 +24,7 @@
     "compositing/frame_sink_bundle_id.mojom",
     "compositing/frame_sink_id.mojom",
     "compositing/frame_timing_details.mojom",
+    "compositing/layer_context.mojom",
     "compositing/local_surface_id.mojom",
     "compositing/paint_filter.mojom",
     "compositing/quads.mojom",
diff --git a/services/viz/public/mojom/compositing/compositor_frame_sink.mojom b/services/viz/public/mojom/compositing/compositor_frame_sink.mojom
index f7fd878..f0515087 100644
--- a/services/viz/public/mojom/compositing/compositor_frame_sink.mojom
+++ b/services/viz/public/mojom/compositing/compositor_frame_sink.mojom
@@ -8,6 +8,7 @@
 import "mojo/public/mojom/base/shared_memory.mojom";
 import "services/viz/public/mojom/compositing/begin_frame_args.mojom";
 import "services/viz/public/mojom/compositing/compositor_frame.mojom";
+import "services/viz/public/mojom/compositing/layer_context.mojom";
 import "services/viz/public/mojom/compositing/local_surface_id.mojom";
 import "services/viz/public/mojom/compositing/frame_timing_details.mojom";
 import "services/viz/public/mojom/compositing/returned_resource.mojom";
@@ -93,6 +94,13 @@
   // are silently ignored.
   InitializeCompositorFrameSinkType(CompositorFrameSinkType type);
 
+  // Binds to the LayerContext interface for this frame sink. Once this is bound
+  // the frame sink is permanently in LayerContext mode and the client should no
+  // longer submit frames through the CompositorFrameSink interface. Instead
+  // frames will automtaically be submitted by Viz based on the state of a
+  // GPU-side layer tree which can be manipulated through this LayerContext.
+  BindLayerContext(PendingLayerContext context);
+
   // Informs the display compositor the IDs of the thread involved in frame
   // production. This is used on Android PerformanceHint API to dynamically
   // adjust performance to allow power saving.
diff --git a/services/viz/public/mojom/compositing/layer_context.mojom b/services/viz/public/mojom/compositing/layer_context.mojom
new file mode 100644
index 0000000..84b8e1b
--- /dev/null
+++ b/services/viz/public/mojom/compositing/layer_context.mojom
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module viz.mojom;
+
+import "ui/gfx/geometry/mojom/geometry.mojom";
+import "services/viz/public/mojom/compositing/begin_frame_args.mojom";
+import "services/viz/public/mojom/compositing/local_surface_id.mojom";
+
+// Metadata about a layer tree to be updated with each LayerContext commit.
+struct LayerTreeUpdate {
+  gfx.mojom.Rect device_viewport;
+  float device_scale_factor;
+  LocalSurfaceId local_surface_id_from_parent;
+};
+
+// Drives updates to a GPU-side LayerTreeHostImpl from its corresponding
+// client-side (e.g. renderer- or browser-side) LayerTreeHost.
+interface LayerContext {
+  // Updates the LocalSurfaceId associated with the tree.
+  SetTargetLocalSurfaceId(LocalSurfaceId id);
+
+  // Globally controls whether the tree contents are visible.
+  SetVisible(bool visible);
+
+  // Flushes pending updates from the client to the LayerTreeHostImpl.
+  Commit(LayerTreeUpdate update);
+};
+
+// Provides feedback from a GPU-side LayerTreeHostImpl to its corresponding
+// client-side (e.g. renderer- or browser-side) LayerTreeHost.
+interface LayerContextClient {
+  // Sent by the LayerTreeHostImpl when it needs to produce a new frame soon and
+  // the client had previously indicated that it wants an opporunity to make
+  // changes to the tree before that frame is drawn.
+  OnRequestCommitForFrame(BeginFrameArgs args);
+};
+
+// Parameters needed to bind a LayerContext endpoint via a CompositorFrameSink.
+struct PendingLayerContext {
+  // TODO(https://crbug.com/1431762): De-associate these interfaces from
+  // CompositorFrameSink.
+  pending_associated_receiver<LayerContext> receiver;
+  pending_associated_remote<LayerContextClient> client;
+};
+
diff --git a/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h b/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h
index 6b9e14c..3e59679 100644
--- a/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h
+++ b/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h
@@ -13,6 +13,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink-forward.h"
 
@@ -64,6 +65,8 @@
   MOCK_METHOD1(SetPreferredFrameInterval, void(base::TimeDelta));
   MOCK_METHOD1(InitializeCompositorFrameSinkType,
                void(viz::mojom::CompositorFrameSinkType));
+  MOCK_METHOD1(BindLayerContext,
+               void(viz::mojom::blink::PendingLayerContextPtr));
   MOCK_METHOD1(SetThreadIds, void(const WTF::Vector<int32_t>&));
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index d5260d8..c0a5ea7 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -30,6 +30,7 @@
 #include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h"
 #include "services/viz/public/mojom/compositing/frame_sink_bundle.mojom-blink.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h"
 #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
@@ -152,6 +153,9 @@
     bundle_->InitializeCompositorFrameSinkType(frame_sink_id_.sink_id(), type);
   }
 
+  void BindLayerContext(
+      viz::mojom::blink::PendingLayerContextPtr context) override {}
+
 #if BUILDFLAG(IS_ANDROID)
   void SetThreadIds(const WTF::Vector<int32_t>& thread_ids) override {
     bundle_->SetThreadIds(frame_sink_id_.sink_id(), thread_ids);
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index 6ef6725f..5887c8e 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -31,6 +31,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h"
+#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h"
 #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -116,6 +117,8 @@
   MOCK_METHOD1(DidDeleteSharedBitmap, void(const gpu::Mailbox& id));
   MOCK_METHOD1(InitializeCompositorFrameSinkType,
                void(viz::mojom::CompositorFrameSinkType));
+  MOCK_METHOD1(BindLayerContext,
+               void(viz::mojom::blink::PendingLayerContextPtr));
   MOCK_METHOD1(SetThreadIds, void(const WTF::Vector<int32_t>&));
 
  private: