1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225

cc / mojo_embedder / async_layer_tree_frame_sink.h [blame]

// Copyright 2017 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_ASYNC_LAYER_TREE_FRAME_SINK_H_
#define CC_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_

#include <memory>
#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "cc/mojo_embedder/mojo_embedder_export.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_timing_details_map.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "gpu/ipc/client/client_shared_image_interface.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/direct_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
#include "third_party/abseil-cpp/absl/types/variant.h"

namespace cc {

class LayerContext;
class LayerTreeHostImpl;
class RasterContextProviderWrapper;

namespace mojo_embedder {

// A mojo-based implementation of LayerTreeFrameSink. The typically-used
// implementation for cc instances that do not share a process with the viz
// display compositor.
class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
    : public LayerTreeFrameSink,
      public viz::mojom::CompositorFrameSinkClient,
      public viz::ExternalBeginFrameSourceClient {
 public:
  struct CC_MOJO_EMBEDDER_EXPORT UnboundMessagePipes {
    UnboundMessagePipes();
    ~UnboundMessagePipes();
    UnboundMessagePipes(UnboundMessagePipes&& other);

    bool HasUnbound() const;

    // Only one of |compositor_frame_sink_remote| or
    // |compositor_frame_sink_associated_remote| should be set.
    mojo::PendingRemote<viz::mojom::CompositorFrameSink>
        compositor_frame_sink_remote;
    mojo::PendingAssociatedRemote<viz::mojom::CompositorFrameSink>
        compositor_frame_sink_associated_remote;
    mojo::PendingReceiver<viz::mojom::CompositorFrameSinkClient>
        client_receiver;
  };

  struct CC_MOJO_EMBEDDER_EXPORT InitParams {
    InitParams();
    ~InitParams();

    scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner;
    raw_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager = nullptr;
    std::unique_ptr<viz::SyntheticBeginFrameSource>
        synthetic_begin_frame_source;
    UnboundMessagePipes pipes;
    bool wants_animate_only_begin_frames = false;
    base::PlatformThreadId io_thread_id = base::kInvalidThreadId;
    base::PlatformThreadId main_thread_id = base::kInvalidThreadId;

    // If `true`, the CompositorFrameSinkClient receiver will receive IPC
    // directly to the thread on which the AsyncLayerTreeFrameSink lives, rather
    // than hopping through the I/O thread first. Only usable if the
    // AsyncLayerTreeFrameSink lives on a thread which uses an IO message pump.
    bool use_direct_client_receiver = false;

    // If |true|, presentation feedback will be used on every begin frame to
    // update the vsync parameters of the |synthetic_begin_frame_source|.
    bool use_begin_frame_presentation_feedback = false;

    // If `true`, SetNeedsBeginFrame(true) IPCs are omitted. Instead, the client
    // relies on unsolicited compositor frame submission to notify the server
    // side to start sending BeginFrame requests.
    //
    // Note: SetNeedsBeginFrame(false) IPCs are sent regardless what value
    // `auto_needs_begin_frame` is.
    bool auto_needs_begin_frame = false;

    // Notifies the client wants to throttle sending
    // `DidReceiveCompositorFrameAck` and `ReclaimResources`. Instead merging
    // them into OnBeginFrame. This is set to `true` by default. Users of
    // |this| can optionally opt out from this by setting this to `false`.
    //
    // Note: on the server side, this throttle is also controlled with the
    // `features::kOnBeginFrameAcks` in addition to this control variable.
    bool wants_begin_frame_acks = true;
  };

  AsyncLayerTreeFrameSink(
      scoped_refptr<viz::RasterContextProvider> context_provider,
      scoped_refptr<RasterContextProviderWrapper>
          worker_context_provider_wrapper,
      scoped_refptr<gpu::ClientSharedImageInterface> shared_image_interface,
      InitParams* params);
  AsyncLayerTreeFrameSink(const AsyncLayerTreeFrameSink&) = delete;
  ~AsyncLayerTreeFrameSink() override;

  AsyncLayerTreeFrameSink& operator=(const AsyncLayerTreeFrameSink&) = delete;

  const viz::LocalSurfaceId& local_surface_id() const {
    return local_surface_id_;
  }
  float last_submitted_device_scale_factor() const {
    return last_submitted_device_scale_factor_;
  }
  const gfx::Size& last_submitted_size_in_pixels() const {
    return last_submitted_size_in_pixels_;
  }

  bool auto_needs_begin_frame() const { return auto_needs_begin_frame_; }
  bool needs_begin_frames() const { return needs_begin_frames_; }

  // LayerTreeFrameSink implementation.
  bool BindToClient(LayerTreeFrameSinkClient* client) override;
  void DetachFromClient() override;
  void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) override;
  void SubmitCompositorFrame(viz::CompositorFrame frame,
                             bool hit_test_data_changed) override;
  void DidNotProduceFrame(const viz::BeginFrameAck& ack,
                          FrameSkippedReason reason) override;
  std::unique_ptr<LayerContext> CreateLayerContext(
      LayerTreeHostImpl& host_impl) override;
  void DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,
                               const viz::SharedBitmapId& id) override;
  void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override;

  const viz::HitTestRegionList& get_last_hit_test_data_for_testing() const {
    return last_hit_test_data_;
  }

 private:
  // mojom::CompositorFrameSinkClient implementation:
  void DidReceiveCompositorFrameAck(
      std::vector<viz::ReturnedResource> resources) override;
  void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args,
                    const viz::FrameTimingDetailsMap& timing_details,
                    bool frame_ack,
                    std::vector<viz::ReturnedResource> resources) override;
  void OnBeginFramePausedChanged(bool paused) override;
  void ReclaimResources(std::vector<viz::ReturnedResource> resources) override;
  void OnCompositorFrameTransitionDirectiveProcessed(
      uint32_t sequence_id) override;
  void OnSurfaceEvicted(const viz::LocalSurfaceId& local_surface_id) override;

  // ExternalBeginFrameSourceClient implementation.
  void OnNeedsBeginFrames(bool needs_begin_frames) override;

  void OnMojoConnectionError(uint32_t custom_reason,
                             const std::string& description);

  void UpdateNeedsBeginFramesInternal(bool needs_begin_frames);

  const bool use_direct_client_receiver_;
  bool begin_frames_paused_ = false;
  bool needs_begin_frames_ = false;
  viz::LocalSurfaceId local_surface_id_;
  std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_;
  std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
#if BUILDFLAG(IS_ANDROID)
  base::PlatformThreadId io_thread_id_;
  base::PlatformThreadId main_thread_id_;
#endif

  // Message pipes that will be bound when BindToClient() is called.
  UnboundMessagePipes pipes_;

  mojo::Remote<viz::mojom::CompositorFrameSink> compositor_frame_sink_;
  mojo::AssociatedRemote<viz::mojom::CompositorFrameSink>
      compositor_frame_sink_associated_;
  // One of |compositor_frame_sink_| or |compositor_frame_sink_associated_| will
  // be bound after calling BindToClient(). |compositor_frame_sink_ptr_| will
  // point to message pipe we want to use. It must be declared last and cleared
  // first.
  raw_ptr<viz::mojom::CompositorFrameSink> compositor_frame_sink_ptr_ = nullptr;

  using ClientReceiver = mojo::Receiver<viz::mojom::CompositorFrameSinkClient>;
  using DirectClientReceiver =
      mojo::DirectReceiver<viz::mojom::CompositorFrameSinkClient>;
  absl::variant<absl::monostate, ClientReceiver, DirectClientReceiver>
      client_receiver_;

  THREAD_CHECKER(thread_checker_);
  const bool wants_animate_only_begin_frames_;

  // Please see comment of `InitParams::auto_needs_begin_frame`.
  const bool auto_needs_begin_frame_;
  // Please see comment of `InitParams::wants_begin_frame_acks`.
  const bool wants_begin_frame_acks_;

  viz::HitTestRegionList last_hit_test_data_;

  viz::LocalSurfaceId last_submitted_local_surface_id_;
  float last_submitted_device_scale_factor_ = 1.f;
  gfx::Size last_submitted_size_in_pixels_;

  bool use_begin_frame_presentation_feedback_ = false;

  base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_{this};
};

}  // namespace mojo_embedder
}  // namespace cc

#endif  // CC_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_