| // 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 <variant> |
| #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.h" |
| #include "components/viz/common/frame_timing_details_map.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" |
| |
| namespace viz { |
| class RasterContextProvider; |
| } // namespace viz |
| |
| namespace cc { |
| |
| class LayerContext; |
| class LayerTreeHostImpl; |
| |
| 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; |
| 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; |
| |
| // If true, the client will not receive DidReceiveCompositorFrameAck() and |
| // should not wait for it before submitting another CompositorFrame. |
| bool no_compositor_frame_acks = false; |
| |
| // If true, when `OnNeedsBeginFrames` is called a `ManualSourceId` will be |
| // used to generate the first `OnBeginFrame`. Rather than waiting for |
| // feedback from the `CompositorFrameSink`. To be used with |
| // `auto_needs_begin_frame`. |
| bool manual_begin_frame = false; |
| |
| // If it has value(n), internal begin frame source will be used when n |
| // consecutive "did not produce frame" are observed. It will stop using |
| // internal begin frame source when there's a submitted compositor frame. |
| // This should be mutually exclusive from synthetic_begin_frame_source. |
| // And `auto_needs_begin_frame` will be true if this is set. |
| std::optional<int> |
| num_did_not_produce_frame_before_internal_begin_frame_source; |
| }; |
| |
| AsyncLayerTreeFrameSink( |
| scoped_refptr<viz::RasterContextProvider> context_provider, |
| scoped_refptr<viz::RasterContextProvider> worker_context_provider, |
| 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; |
| void ExportFrameTiming() override; |
| std::unique_ptr<LayerContext> CreateLayerContext( |
| LayerTreeHostImpl& host_impl) override; |
| |
| const viz::HitTestRegionList& get_last_hit_test_data_for_testing() const { |
| return last_hit_test_data_; |
| } |
| |
| bool use_internal_begin_frame_source_for_testing() const { |
| return use_internal_begin_frame_source_; |
| } |
| |
| void SetTimeSourceOfInternalBeginFrameForTesting( |
| std::unique_ptr<viz::DelayBasedTimeSource> source); |
| |
| private: |
| friend class AsyncLayerTreeFrameSinkSimpleTest; |
| |
| // mojom::CompositorFrameSinkClient implementation: |
| void DidReceiveCompositorFrameAck( |
| std::vector<viz::ReturnedResource> resources) override; |
| void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args, |
| const viz::FrameTimingDetailsMap& timing_details, |
| 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; |
| |
| void NotifyNewLocalSurfaceIdExpectedWhilePaused() 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); |
| |
| void UpdateInternalBeginFrameSource(bool use_internal_source); |
| |
| void SendManualBeginFrame(); |
| |
| 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>; |
| std::variant<std::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::no_compositor_frame_acks`. |
| const bool no_compositor_frame_acks_; |
| |
| // Please see comment of `InitParams::manual_begin_frame`. |
| const bool manual_begin_frame_; |
| |
| 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; |
| viz::FrameTimingDetailsMap timing_details_; |
| |
| // Use internal delay based begin frame source when there're many undrawn |
| // frames recently. |
| std::optional<int> |
| num_did_not_produce_frame_before_internal_begin_frame_source_; |
| uint64_t num_did_not_produce_frame_since_last_submit_ = 0; |
| bool use_internal_begin_frame_source_ = false; |
| std::unique_ptr<viz::DelayBasedBeginFrameSource> internal_begin_frame_source_; |
| |
| uint64_t manual_sequence_number_ = 0; |
| |
| base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_{this}; |
| }; |
| |
| } // namespace mojo_embedder |
| } // namespace cc |
| |
| #endif // CC_MOJO_EMBEDDER_ASYNC_LAYER_TREE_FRAME_SINK_H_ |