// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_COMPOSITOR_COMPOSITOR_H_ #define UI_COMPOSITOR_COMPOSITOR_H_ #include #include #include #include "base/callback_forward.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/power_monitor/power_observer.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "cc/metrics/events_metrics_manager.h" #include "cc/metrics/frame_sequence_tracker.h" #include "cc/paint/element_id.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "cc/trees/paint_holding_reason.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/host/host_frame_sink_client.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "services/viz/privileged/mojom/compositing/vsync_parameter_observer.mojom-forward.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkM44.h" #include "ui/compositor/compositor_animation_observer.h" #include "ui/compositor/compositor_export.h" #include "ui/compositor/compositor_lock.h" #include "ui/compositor/compositor_observer.h" #include "ui/compositor/layer_animator_collection.h" #include "ui/compositor/throughput_tracker.h" #include "ui/compositor/throughput_tracker_host.h" #include "ui/gfx/display_color_spaces.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/overlay_transform.h" namespace base { class SingleThreadTaskRunner; } namespace cc { class AnimationHost; class AnimationTimeline; class Layer; class LayerTreeDebugState; class LayerTreeFrameSink; class LayerTreeSettings; class TaskGraphRunner; } namespace gfx { namespace mojom { class DelegatedInkPointRenderer; } // namespace mojom struct PresentationFeedback; class Rect; class Size; } namespace gpu { class GpuMemoryBufferManager; } namespace viz { namespace mojom { class DisplayPrivate; class ExternalBeginFrameController; } // namespace mojom class ContextProvider; class HostFrameSinkManager; class LocalSurfaceId; class RasterContextProvider; } // namespace viz namespace ui { class Compositor; class Layer; class ScopedAnimationDurationScaleMode; class ScrollInputHandler; class ThroughputTracker; struct PendingBeginFrameArgs; constexpr int kCompositorLockTimeoutMs = 67; // This class abstracts the creation of the 3D context for the compositor. It is // a global object. class COMPOSITOR_EXPORT ContextFactory { public: virtual ~ContextFactory() {} // Creates an output surface for the given compositor. The factory may keep // per-compositor data (e.g. a shared context), that needs to be cleaned up // by calling RemoveCompositor when the compositor gets destroyed. virtual void CreateLayerTreeFrameSink( base::WeakPtr compositor) = 0; // Return a reference to a shared offscreen context provider usable from the // main thread. virtual scoped_refptr SharedMainThreadContextProvider() = 0; // Return a reference to a shared offscreen context provider usable from the // main thread. virtual scoped_refptr SharedMainThreadRasterContextProvider() = 0; // Destroys per-compositor data. virtual void RemoveCompositor(Compositor* compositor) = 0; // Gets the GPU memory buffer manager. virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() = 0; // Gets the task graph runner. virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0; // Allocate a new client ID for the display compositor. virtual viz::FrameSinkId AllocateFrameSinkId() = 0; // Allocates a new capture ID for a layer subtree within a frame sink. virtual viz::SubtreeCaptureId AllocateSubtreeCaptureId() = 0; // Gets the frame sink manager host instance. virtual viz::HostFrameSinkManager* GetHostFrameSinkManager() = 0; }; // Compositor object to take care of GPU painting. // A Browser compositor object is responsible for generating the final // displayable form of pixels comprising a single widget's contents. It draws an // appropriately transformed texture for each transformed view in the widget's // view hierarchy. class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, public cc::LayerTreeHostClient, public cc::LayerTreeHostSingleThreadClient, public viz::HostFrameSinkClient, public ThroughputTrackerHost { public: Compositor(const viz::FrameSinkId& frame_sink_id, ui::ContextFactory* context_factory, scoped_refptr task_runner, bool enable_pixel_canvas, bool use_external_begin_frame_control = false, bool force_software_compositor = false, bool enable_compositing_based_throttling = false, size_t memory_limit_when_visible_mb = 0); Compositor(const Compositor&) = delete; Compositor& operator=(const Compositor&) = delete; ~Compositor() override; ui::ContextFactory* context_factory() { return context_factory_; } void AddChildFrameSink(const viz::FrameSinkId& frame_sink_id); void RemoveChildFrameSink(const viz::FrameSinkId& frame_sink_id); void SetLayerTreeFrameSink(std::unique_ptr surface, viz::mojom::DisplayPrivate* display_private); void SetExternalBeginFrameController(viz::mojom::ExternalBeginFrameController* external_begin_frame_controller); // Called when a child surface is about to resize. void OnChildResizing(); // Schedules a redraw of the layer tree associated with this compositor. void ScheduleDraw(); // Sets the root of the layer tree drawn by this Compositor. The root layer // must have no parent. The compositor's root layer is reset if the root layer // is destroyed. NULL can be passed to reset the root layer, in which case the // compositor will stop drawing anything. // The Compositor does not own the root layer. const Layer* root_layer() const { return root_layer_; } Layer* root_layer() { return root_layer_; } void SetRootLayer(Layer* root_layer); // HideHelper temporarily hides the root layer and replaces it with a // temporary layer, without calling SetRootLayer (but doing much of the work // that SetRootLayer does). During that time we must disable ticking // of animations, since animations that animate layers that are not in // cc's layer tree must not tick. These methods make those changes // and record/reflect that state. void DisableAnimations(); void EnableAnimations(); bool animations_are_enabled() const { return animations_are_enabled_; } cc::AnimationTimeline* GetAnimationTimeline() const; // The scale factor of the device that this compositor is // compositing layers on. float device_scale_factor() const { return device_scale_factor_; } // Gets and sets the color matrix used to transform the output colors of what // this compositor renders. const SkM44& display_color_matrix() const { return display_color_matrix_; } void SetDisplayColorMatrix(const SkM44& matrix); // Where possible, draws are scissored to a damage region calculated from // changes to layer properties. This bypasses that and indicates that // the whole frame needs to be drawn. void ScheduleFullRedraw(); // Schedule redraw and append damage_rect to the damage region calculated // from changes to layer properties. void ScheduleRedrawRect(const gfx::Rect& damage_rect); #if BUILDFLAG(IS_WIN) // Until this is called with |should| true then both DisableSwapUntilResize() // and ReenableSwap() do nothing. void SetShouldDisableSwapUntilResize(bool should); // Attempts to immediately swap a frame with the current size if possible, // then disables swapping on this surface until it is resized. void DisableSwapUntilResize(); void ReenableSwap(); #endif // Sets the compositor's device scale factor and size. void SetScaleAndSize(float scale, const gfx::Size& size_in_pixel, const viz::LocalSurfaceId& local_surface_id); // Set the output color profile into which this compositor should render. Also // sets the SDR white level (in nits) used to scale HDR color space primaries. void SetDisplayColorSpaces( const gfx::DisplayColorSpaces& display_color_spaces); const gfx::DisplayColorSpaces& display_color_spaces() const { return display_color_spaces_; } // Set the transform/rotation info for the display output surface. void SetDisplayTransformHint(gfx::OverlayTransform hint); gfx::OverlayTransform display_transform_hint() const { return host_->display_transform_hint(); } // Returns the size of the widget that is being drawn to in pixel coordinates. const gfx::Size& size() const { return size_; } // Sets the background color used for areas that aren't covered by // the |root_layer|. void SetBackgroundColor(SkColor color); // Inform the display corresponding to this compositor if it is visible. When // false it does not need to produce any frames. Visibility is reset for each // call to CreateLayerTreeFrameSink. void SetVisible(bool visible); // Gets the visibility of the underlying compositor. bool IsVisible(); // Gets or sets the scroll offset for the given layer in step with the // cc::InputHandler. Returns true if the layer is active on the impl side. bool GetScrollOffsetForLayer(cc::ElementId element_id, gfx::PointF* offset) const; bool ScrollLayerTo(cc::ElementId element_id, const gfx::PointF& offset); // Mac path for transporting vsync parameters to the display. Other platforms // update it via the BrowserCompositorLayerTreeFrameSink directly. void SetDisplayVSyncParameters(base::TimeTicks timebase, base::TimeDelta interval); void AddVSyncParameterObserver( mojo::PendingRemote observer); // Sets the widget for the compositor to render into. void SetAcceleratedWidget(gfx::AcceleratedWidget widget); // Releases the widget previously set through SetAcceleratedWidget(). // After returning it will not be used for rendering anymore. // The compositor must be set to invisible when taking away a widget. gfx::AcceleratedWidget ReleaseAcceleratedWidget(); gfx::AcceleratedWidget widget() const; // This flag is used to force a compositor into software compositing even tho // in general chrome is using gpu compositing. This allows the compositor to // be created without a gpu context, and does not go through the gpu path at // all. This flag can not be used with a compositor that embeds any external // content via a SurfaceLayer, as they would not agree on what compositing // mode to use for resources, but may be used eg for tooltip windows. bool force_software_compositor() { return force_software_compositor_; } // Returns the main thread task runner this compositor uses. Users of the // compositor generally shouldn't use this. scoped_refptr task_runner() const { return task_runner_; } // Compositor does not own observers. It is the responsibility of the // observer to remove itself when it is done observing. void AddObserver(CompositorObserver* observer); void RemoveObserver(CompositorObserver* observer); bool HasObserver(const CompositorObserver* observer) const; void AddAnimationObserver(CompositorAnimationObserver* observer); void RemoveAnimationObserver(CompositorAnimationObserver* observer); bool HasAnimationObserver(const CompositorAnimationObserver* observer) const; // Creates a compositor lock. Returns NULL if it is not possible to lock at // this time (i.e. we're waiting to complete a previous unlock). If the // timeout is null, then no timeout is used. std::unique_ptr GetCompositorLock( CompositorLockClient* client, base::TimeDelta timeout = base::Milliseconds(kCompositorLockTimeoutMs)) { return lock_manager_.GetCompositorLock(client, timeout, host_->DeferMainFrameUpdate()); } // Registers a callback that is run when the next frame successfully makes it // to the screen (it's entirely possible some frames may be dropped between // the time this is called and the callback is run). // See ui/gfx/presentation_feedback.h for details on the args (TimeTicks is // always non-zero). using PresentationTimeCallback = base::OnceCallback; void RequestPresentationTimeForNextFrame(PresentationTimeCallback callback); void IssueExternalBeginFrame( const viz::BeginFrameArgs& args, bool force, base::OnceCallback callback); // Creates a ThroughputTracker for tracking this Compositor. ThroughputTracker RequestNewThroughputTracker(); // Returns a percentage of dropped frames of the last second. double GetPercentDroppedFrames() const; // Activates a scoped monitor for the current event to track its metrics. // `done_callback` is called when the monitor goes out of scope. std::unique_ptr GetScopedEventMetricsMonitor( cc::EventsMetricsManager::ScopedMonitor::DoneCallback done_callback); // LayerTreeHostClient implementation. void WillBeginMainFrame() override {} void DidBeginMainFrame() override {} void OnDeferMainFrameUpdatesChanged(bool) override {} void OnDeferCommitsChanged( bool, cc::PaintHoldingReason, absl::optional) override {} void WillUpdateLayers() override {} void DidUpdateLayers() override; void BeginMainFrame(const viz::BeginFrameArgs& args) override; void BeginMainFrameNotExpectedSoon() override; void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void UpdateLayerTreeHost() override; void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override { } void UpdateCompositorScrollState( const cc::CompositorCommitData& commit_data) override {} void RequestNewLayerTreeFrameSink() override; void DidInitializeLayerTreeFrameSink() override {} void DidFailToInitializeLayerTreeFrameSink() override; void WillCommit(const cc::CommitState&) override {} void DidCommit(base::TimeTicks, base::TimeTicks) 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, cc::ActiveFrameSequenceTrackers trackers) override {} std::unique_ptr GetBeginMainFrameMetrics() override; std::unique_ptr GetWebVitalMetrics() override; void NotifyThroughputTrackerResults( cc::CustomTrackerResults results) override; void DidObserveFirstScrollDelay( base::TimeDelta first_scroll_delay, base::TimeTicks first_scroll_timestamp) override {} void ReportEventLatency( std::vector latencies) override; // cc::LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override; void DidLoseLayerTreeFrameSink() override {} void FrameIntervalUpdated(base::TimeDelta interval) override; void FrameSinksToThrottleUpdated( const base::flat_set& ids) override; // viz::HostFrameSinkClient implementation. void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override; void OnFrameTokenChanged(uint32_t frame_token, base::TimeTicks activation_time) override; // ThroughputTrackerHost implementation. void StartThroughputTracker( TrackerId tracker_id, ThroughputTrackerHost::ReportCallback callback) override; bool StopThroughtputTracker(TrackerId tracker_id) override; void CancelThroughtputTracker(TrackerId tracker_id) override; // base::PowerSuspendObserver: void OnResume() override; // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch // of lacros-chrome is complete. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) void OnCompleteSwapWithNewSize(const gfx::Size& size); #endif bool IsLocked() { return lock_manager_.IsLocked(); } void SetOutputIsSecure(bool output_is_secure); const cc::LayerTreeDebugState& GetLayerTreeDebugState() const; void SetLayerTreeDebugState(const cc::LayerTreeDebugState& debug_state); LayerAnimatorCollection* layer_animator_collection() { return &layer_animator_collection_; } const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; } int activated_frame_count() const { return activated_frame_count_; } float refresh_rate() const { return refresh_rate_; } bool use_external_begin_frame_control() const { return use_external_begin_frame_control_; } void SetAllowLocksToExtendTimeout(bool allowed) { lock_manager_.set_allow_locks_to_extend_timeout(allowed); } // If true, all paint commands are recorded at pixel size instead of DIP. bool is_pixel_canvas() const { return is_pixel_canvas_; } ScrollInputHandler* scroll_input_handler() const { return scroll_input_handler_.get(); } virtual void SetDelegatedInkPointRenderer( mojo::PendingReceiver receiver); const cc::LayerTreeSettings& GetLayerTreeSettings() const; private: friend class base::RefCounted; friend class TotalAnimationThroughputReporter; // Called when collected metrics for the tracker of |tracker_id| is ready. void ReportMetricsForTracker( int tracker_id, const cc::FrameSequenceMetrics::CustomReportData& data); gfx::Size size_; raw_ptr context_factory_; // |display_private_| can be null for: // 1. Tests that don't set |display_private_|. // 2. Intermittently on creation or if there is some kind of error (GPU crash, // GL context loss, etc.) that triggers reinitializing message pipes to the // GPU process RootCompositorFrameSinkImpl. // Therefore, it should always be null checked for safety before use. // // These pointers are owned by |context_factory_|, and must be reset before // calling RemoveCompositor(); raw_ptr display_private_ = nullptr; raw_ptr external_begin_frame_controller_ = nullptr; std::unique_ptr pending_begin_frame_args_; // The root of the Layer tree drawn by this compositor. raw_ptr root_layer_ = nullptr; base::ObserverList::Unchecked observer_list_; base::ObserverList::Unchecked animation_observer_list_; gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; // A sequence number of a current compositor frame for use with metrics. int activated_frame_count_ = 0; // Current vsync refresh rate per second. Initialized to 60hz as a reasonable // value until first begin frame arrives with the real refresh rate. float refresh_rate_ = 60.f; // A map from child id to parent id. std::unordered_set child_frame_sinks_; bool widget_valid_ = false; bool layer_tree_frame_sink_requested_ = false; const viz::FrameSinkId frame_sink_id_; scoped_refptr root_web_layer_; std::unique_ptr animation_host_; std::unique_ptr host_; base::WeakPtr input_handler_weak_; scoped_refptr task_runner_; // Snapshot of last set vsync parameters, to avoid redundant IPCs. base::TimeTicks vsync_timebase_; base::TimeDelta vsync_interval_ = viz::BeginFrameArgs::DefaultInterval(); bool has_vsync_params_ = false; const bool use_external_begin_frame_control_; const bool force_software_compositor_; // The device scale factor of the monitor that this compositor is compositing // layers on. float device_scale_factor_ = 0.f; LayerAnimatorCollection layer_animator_collection_; scoped_refptr animation_timeline_; std::unique_ptr slow_animations_; SkM44 display_color_matrix_; gfx::DisplayColorSpaces display_color_spaces_; bool output_is_secure_ = false; // If true, all paint commands are recorded at pixel size instead of DIP. const bool is_pixel_canvas_; CompositorLockManager lock_manager_; std::unique_ptr scroll_input_handler_; #if BUILDFLAG(IS_WIN) bool should_disable_swap_until_resize_ = false; #endif // Set in DisableSwapUntilResize and reset when a resize happens. bool disabled_swap_until_resize_ = false; bool animations_are_enabled_ = true; TrackerId next_throughput_tracker_id_ = 1u; struct TrackerState { TrackerState(); TrackerState(TrackerState&&); TrackerState& operator=(TrackerState&&); ~TrackerState(); // Whether a tracker is waiting for report and `report_callback` should be // invoked. This is set to true when a tracker is stopped. bool should_report = false; // Whether the report for a tracker has happened. This is set when an // involuntary report happens before the tracker is stopped and set // `should_report` field above. bool report_attempted = false; // Invoked to send report to the owner of a tracker. ThroughputTrackerHost::ReportCallback report_callback; }; using ThroughputTrackerMap = base::flat_map; ThroughputTrackerMap throughput_tracker_map_; base::WeakPtrFactory context_creation_weak_ptr_factory_{this}; base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace ui #endif // UI_COMPOSITOR_COMPOSITOR_H_