chromium/ash/frame_sink/frame_sink_host.h

// 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 ASH_FRAME_SINK_FRAME_SINK_HOST_H_
#define ASH_FRAME_SINK_FRAME_SINK_HOST_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/frame_sink/ui_resource_manager.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/presentation_feedback.h"

namespace cc {
class LayerTreeFrameSink;
}  // namespace cc

namespace ash {

class FrameSinkHolder;

// Base class for surfaces that render content by creating independent
// compositor frames and submitting them directly to display compositor.
//
// FrameSinkHost encapsulates interactions with the display compositor and
// manages relevant resources. Child classes override CreateCompositorFrame() to
// control compositor frame creation behavior.
//
// Note: The host_window must outlive the FrameSinkHost.
class ASH_EXPORT FrameSinkHost : public aura::WindowObserver {
 public:
  using PresentationCallback =
      base::RepeatingCallback<void(const gfx::PresentationFeedback&)>;

  FrameSinkHost();

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

  ~FrameSinkHost() override;

  aura::Window* host_window() { return host_window_; }
  const aura::Window* host_window() const { return host_window_; }

  void SetPresentationCallback(PresentationCallback callback);

  // Initializes the FrameSinkHost on the host_window.
  virtual void Init(aura::Window* host_window);

  virtual void InitForTesting(
      aura::Window* host_window,
      std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink);

  // Updates the surface by submitting a compositor frame. With
  // synchronous_draw as true, we send a compositor frame as soon as we call the
  // UpdateSurface method otherwise we draw asynchronously where we wait till
  // display_compositor requests for a new frame.
  // Note: Calling this method turns off the auto updating of the surface if
  // enabled.
  void UpdateSurface(const gfx::Rect& content_rect,
                     const gfx::Rect& damage_rect,
                     bool synchronous_draw);

  // Updates the surface by submitting frames asynchronously. Compared to
  // `UpdateSurface()`, where we submit a single frame, after calling
  // this method, we keep submitting frames asynchronously. It should be used if
  // we expect that there are continuous updates within the content_rect.
  void AutoUpdateSurface(const gfx::Rect& content_rect,
                         const gfx::Rect& damage_rect);

  // Overridden from aura::WindowObserver
  void OnWindowDestroying(aura::Window* window) override;

 protected:
  // Creates a compositor frame that can be sent to the display compositor.
  // `begin_frame_ack` is a token that needs to be attached to the compositor
  // frame being created.
  // `resource_manager` helps manage resources that can be attached to the
  // compositor frame and also give us a pool of reusable resources.
  // `auto_update` if true means that we are continuously submitting frames
  // asynchronously and should redraw full surface regardless of damage.
  // `last_submitted_frame_size` and `last_submitted_frame_dsf`
  // can be used to determine if a new surface needs to be identified on the
  // `host_window_`.
  // Returns nullptr if a compositor frame cannot be created.
  virtual std::unique_ptr<viz::CompositorFrame> CreateCompositorFrame(
      const viz::BeginFrameAck& begin_frame_ack,
      UiResourceManager& resource_manager,
      bool auto_update,
      const gfx::Size& last_submitted_frame_size,
      float last_submitted_frame_dsf) = 0;

  // Callback invoked when underlying frame sink holder gets the first begin
  // frame from viz. This signifies that the gpu process has been fully
  // initialized.
  virtual void OnFirstFrameRequested();

  const gfx::Rect& GetTotalDamage() const { return total_damage_rect_; }

  void UnionDamage(const gfx::Rect& rect) { total_damage_rect_.Union(rect); }

  void IntersectDamage(const gfx::Rect& rect) {
    total_damage_rect_.Intersect(rect);
  }

  void ResetDamage() { total_damage_rect_ = gfx::Rect(); }

  const gfx::Rect& GetContentRect() const { return content_rect_; }

 private:
  void InitFrameSinkHolder(
      aura::Window* host_window,
      std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink);

  void SetHostWindow(aura::Window* host_window);

  void InitInternal(
      aura::Window* host_window,
      std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink);

  // Observation to track the lifetime of `host_window_`.
  base::ScopedObservation<aura::Window, aura::WindowObserver>
      host_window_observation_{this};

  // The window on which LayerTreeFrameSink is created on.
  raw_ptr<aura::Window> host_window_ = nullptr;

  // The bounds of the content to be displayed in host window coordinates.
  gfx::Rect content_rect_;

  // The damage rect in host window coordinates.
  gfx::Rect total_damage_rect_;

  // Holds the LayerTreeFrameSink. For proper deletion of in flight
  // resources, lifetime of the FrameSinkHolder is extended to either the root
  // window of the`host_window` or till we reclaim all the exported resources
  // to the display compositor. See `FrameSinkHolder` implementation for
  // details. https://crbug.com/765763
  std::unique_ptr<FrameSinkHolder> frame_sink_holder_;

  base::WeakPtrFactory<FrameSinkHost> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_FRAME_SINK_FRAME_SINK_HOST_H_