chromium/content/browser/android/synchronous_compositor_host.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_HOST_H_
#define CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_HOST_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/task/single_thread_task_runner.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "content/common/content_export.h"
#include "content/public/browser/android/synchronous_compositor.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
#include "third_party/blink/public/mojom/input/synchronous_compositor.mojom.h"
#include "ui/android/view_android.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/size_f.h"

namespace ui {
struct DidOverscrollParams;
}

namespace viz {
class HostFrameSinkManager;
}

namespace content {

class RenderProcessHost;
class RenderWidgetHostViewAndroid;
class SynchronousCompositorClient;
class SynchronousCompositorSyncCallBridge;

class CONTENT_EXPORT SynchronousCompositorHost
    : public SynchronousCompositor,
      public blink::mojom::SynchronousCompositorHost,
      public viz::BeginFrameObserver {
 public:
  static std::unique_ptr<SynchronousCompositorHost> Create(
      RenderWidgetHostViewAndroid* rwhva,
      const viz::FrameSinkId& frame_sink_id,
      viz::HostFrameSinkManager* host_frame_sink_manager);

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

  ~SynchronousCompositorHost() override;

  // SynchronousCompositor overrides.
  void OnCompositorVisible() override;
  void OnCompositorHidden() override;
  scoped_refptr<FrameFuture> DemandDrawHwAsync(
      const gfx::Size& viewport_size,
      const gfx::Rect& viewport_rect_for_tile_priority,
      const gfx::Transform& transform_for_tile_priority) override;
  bool DemandDrawSw(SkCanvas* canvas, bool software_canvas) override;
  void ReturnResources(uint32_t layer_tree_frame_sink_id,
                       std::vector<viz::ReturnedResource> resources) override;
  void OnCompositorFrameTransitionDirectiveProcessed(
      uint32_t layer_tree_frame_sink_id,
      uint32_t sequence_id) override;
  void DidPresentCompositorFrames(viz::FrameTimingDetailsMap timing_details,
                                  uint32_t frame_token) override;
  void SetMemoryPolicy(size_t bytes_limit) override;
  float GetVelocityInPixelsPerSecond() override;
  void DidBecomeActive() override;
  void DidChangeRootLayerScrollOffset(const gfx::PointF& root_offset) override;
  void SynchronouslyZoomBy(float zoom_delta, const gfx::Point& anchor) override;
  void OnComputeScroll(base::TimeTicks animation_time) override;
  void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source) override;
  void DidInvalidate() override;
  void WasEvicted() override;

  ui::ViewAndroid::CopyViewCallback GetCopyViewCallback();
  void DidOverscroll(const ui::DidOverscrollParams& over_scroll_params);

  // Called by SynchronousCompositorSyncCallBridge.
  void UpdateFrameMetaData(
      uint32_t version,
      viz::CompositorFrameMetadata frame_metadata,
      std::optional<viz::LocalSurfaceId> new_local_surface_id);
  void BeginFrameComplete(
      blink::mojom::SyncCompositorCommonRendererParamsPtr params);

  // Called when the mojo channel should be created.
  void InitMojo();

  SynchronousCompositorClient* client() { return client_; }

  RenderProcessHost* GetRenderProcessHost();

  void RequestOneBeginFrame();

  void AddBeginFrameCompletionCallback(base::OnceClosure callback);

  const viz::FrameSinkId& GetFrameSinkId() const { return frame_sink_id_; }
  viz::SurfaceId GetSurfaceId() const;

  // blink::mojom::SynchronousCompositorHost overrides.
  void LayerTreeFrameSinkCreated() override;
  void UpdateState(
      blink::mojom::SyncCompositorCommonRendererParamsPtr params) override;
  void SetNeedsBeginFrames(bool needs_begin_frames) override;
  void SetThreadIds(const std::vector<int32_t>& thread_ids) override;

  // viz::BeginFrameObserver implementation.
  void OnBeginFrame(const viz::BeginFrameArgs& args) override;
  const viz::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
  void OnBeginFrameSourcePausedChanged(bool paused) override;
  bool WantsAnimateOnlyBeginFrames() const override;

 private:
  enum BeginFrameRequestType {
    BEGIN_FRAME = 1 << 0,
    PERSISTENT_BEGIN_FRAME = 1 << 1
  };

  class ScopedSendZeroMemory;
  struct SharedMemoryWithSize;
  friend class ScopedSetZeroMemory;
  friend class SynchronousCompositorBase;
  FRIEND_TEST_ALL_PREFIXES(SynchronousCompositorBrowserTest,
                           RenderWidgetHostViewAndroidReuse);

  SynchronousCompositorHost(RenderWidgetHostViewAndroid* rwhva,
                            const viz::FrameSinkId& frame_sink_id,
                            viz::HostFrameSinkManager* host_frame_sink_manager,
                            bool use_in_proc_software_draw);
  SynchronousCompositor::Frame DemandDrawHw(
      const gfx::Size& viewport_size,
      const gfx::Rect& viewport_rect_for_tile_priority,
      const gfx::Transform& transform_for_tile_priority);
  bool DemandDrawSwInProc(SkCanvas* canvas);
  void SetSoftwareDrawSharedMemoryIfNeeded(size_t stride, size_t buffer_size);
  void SendZeroMemory();
  blink::mojom::SynchronousCompositor* GetSynchronousCompositor();
  // Whether the synchronous compositor host is ready to
  // handle blocking calls.
  bool IsReadyForSynchronousCall();
  void UpdateRootLayerStateOnClient();

  void SendBeginFramePaused();
  void SendBeginFrame(viz::BeginFrameArgs args);
  void AddBeginFrameRequest(BeginFrameRequestType request);
  void ClearBeginFrameRequest(BeginFrameRequestType request);

  const raw_ptr<RenderWidgetHostViewAndroid> rwhva_;
  const raw_ptr<SynchronousCompositorClient> client_;
  const viz::FrameSinkId frame_sink_id_;
  const raw_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_;
  const bool use_in_process_zero_copy_software_draw_;
  mojo::AssociatedRemote<blink::mojom::SynchronousCompositor> sync_compositor_;
  mojo::AssociatedReceiver<blink::mojom::SynchronousCompositorHost>
      host_receiver_{this};

  viz::LocalSurfaceId local_surface_id_;

  bool registered_with_filter_ = false;

  size_t bytes_limit_;
  std::unique_ptr<SharedMemoryWithSize> software_draw_shm_;

  // Make sure to send a synchronous IPC that succeeds first before sending
  // asynchronous ones. This shouldn't be needed. However we may have come
  // to rely on sending a synchronous message first on initialization. So
  // with an abundance of caution, keep that behavior until we are sure this
  // isn't required.
  bool allow_async_draw_ = false;

  // Indicates begin frames are paused from the browser.
  bool begin_frame_paused_ = false;

  // Updated by both renderer and browser. This is in physical pixels.
  gfx::PointF root_scroll_offset_;

  float velocity_in_pixels_per_second_ = 0.f;
  base::TimeDelta last_begin_frame_time_delta_;

  // Indicates that whether OnComputeScroll is called or overridden. The
  // fling_controller should advance the fling only when OnComputeScroll is not
  // overridden.
  bool on_compute_scroll_called_ = false;

  // Whether `DemandDrawHwAsync` has ever been called.
  bool draw_hw_called_ = false;

  // From renderer.
  uint32_t renderer_param_version_;
  uint32_t need_invalidate_count_;
  bool invalidate_needs_draw_;
  uint32_t did_activate_pending_tree_count_;
  uint32_t frame_metadata_version_ = 0u;
  // Physical pixel when use-zoom-for-dsf is enabled, otherwise in dip.
  gfx::PointF max_scroll_offset_;
  gfx::SizeF scrollable_size_;
  float page_scale_factor_ = 0.f;
  float min_page_scale_factor_ = 0.f;
  float max_page_scale_factor_ = 0.f;

  // If the last surface was evicted.
  bool was_evicted_ = false;

  scoped_refptr<SynchronousCompositorSyncCallBridge> bridge_;

  // Indicates whether and for what reason a request for begin frames has been
  // issued. Used to control action dispatch at the next |OnBeginFrame()| call.
  uint32_t outstanding_begin_frame_requests_ = 0;

  uint32_t num_invalidates_since_last_draw_ = 0u;
  uint32_t num_begin_frames_to_skip_ = 0u;

  // The begin frame source being observed.  Null if none.
  raw_ptr<viz::BeginFrameSource> begin_frame_source_ = nullptr;
  viz::BeginFrameArgs last_begin_frame_args_;
  viz::FrameTimingDetailsMap timing_details_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_HOST_H_