| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ |
| #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/circular_deque.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/raw_ptr_exclusion.h" |
| #include "base/observer_list.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/timer/timer.h" |
| #include "base/types/pass_key.h" |
| #include "build/build_config.h" |
| #include "components/viz/common/display/renderer_settings.h" |
| #include "components/viz/common/resources/resource_id.h" |
| #include "components/viz/service/display/display_compositor_memory_and_task_controller.h" |
| #include "components/viz/service/display/skia_output_surface.h" |
| #include "components/viz/service/viz_service_export.h" |
| #include "gpu/command_buffer/common/sync_token.h" |
| #include "gpu/ipc/common/vulkan_ycbcr_info.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" |
| #include "third_party/skia/include/core/SkOverdrawCanvas.h" |
| #include "third_party/skia/include/core/SkSurfaceCharacterization.h" |
| #include "ui/gfx/presentation_feedback.h" |
| |
| namespace gfx { |
| namespace mojom { |
| class DelegatedInkPointRenderer; |
| } // namespace mojom |
| } // namespace gfx |
| |
| namespace gpu { |
| class SharedImageRepresentationFactory; |
| struct SwapBuffersCompleteParams; |
| } // namespace gpu |
| |
| namespace skgpu::graphite { |
| class Recorder; |
| class Recording; |
| } // namespace skgpu::graphite |
| |
| namespace viz { |
| |
| class ImageContextImpl; |
| class SkiaOutputSurfaceDependency; |
| class SkiaOutputSurfaceImplOnGpu; |
| |
| // The SkiaOutputSurface implementation. It is the output surface for |
| // SkiaRenderer. It lives on the compositor thread, but it will post tasks |
| // to the GPU thread for initializing. Currently, SkiaOutputSurfaceImpl |
| // create a SkiaOutputSurfaceImplOnGpu on the GPU thread. It will be used |
| // for creating a SkSurface from the default framebuffer and providing the |
| // SkSurfaceCharacterization for the SkSurface. And then SkiaOutputSurfaceImpl |
| // will create SkDeferredDisplayListRecorder and SkCanvas for SkiaRenderer to |
| // render into. In SwapBuffers, it detaches a SkDeferredDisplayList from the |
| // recorder and plays it back on the framebuffer SkSurface on the GPU thread |
| // through SkiaOutputSurfaceImpleOnGpu. |
| class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface { |
| public: |
| static std::unique_ptr<SkiaOutputSurface> Create( |
| DisplayCompositorMemoryAndTaskController* display_controller, |
| const RendererSettings& renderer_settings, |
| const DebugRendererSettings* debug_settings); |
| |
| SkiaOutputSurfaceImpl( |
| base::PassKey<SkiaOutputSurfaceImpl> pass_key, |
| DisplayCompositorMemoryAndTaskController* display_controller, |
| const RendererSettings& renderer_settings, |
| const DebugRendererSettings* debug_settings); |
| ~SkiaOutputSurfaceImpl() override; |
| |
| SkiaOutputSurfaceImpl(const SkiaOutputSurfaceImpl&) = delete; |
| SkiaOutputSurfaceImpl& operator=(const SkiaOutputSurfaceImpl&) = delete; |
| |
| // OutputSurface implementation: |
| gpu::SurfaceHandle GetSurfaceHandle() const override; |
| void BindToClient(OutputSurfaceClient* client) override; |
| void SetDrawRectangle(const gfx::Rect& draw_rectangle) override; |
| void SetEnableDCLayers(bool enable) override; |
| void EnsureBackbuffer() override; |
| void DiscardBackbuffer() override; |
| void Reshape(const ReshapeParams& params) override; |
| void SetUpdateVSyncParametersCallback( |
| UpdateVSyncParametersCallback callback) override; |
| void SetGpuVSyncEnabled(bool enabled) override; |
| void SetGpuVSyncCallback(GpuVSyncCallback callback) override; |
| void SetVSyncDisplayID(int64_t display_id) override; |
| void SetDisplayTransformHint(gfx::OverlayTransform transform) override; |
| gfx::OverlayTransform GetDisplayTransform() override; |
| void SwapBuffers(OutputSurfaceFrame frame) override; |
| bool IsDisplayedAsOverlayPlane() const override; |
| gpu::Mailbox GetOverlayMailbox() const override; |
| void SetNeedsSwapSizeNotifications( |
| bool needs_swap_size_notifications) override; |
| base::ScopedClosureRunner GetCacheBackBufferCb() override; |
| gfx::Rect GetCurrentFramebufferDamage() const override; |
| void SetFrameRate(float frame_rate) override; |
| void SetNeedsMeasureNextDrawLatency() override; |
| |
| // SkiaOutputSurface implementation: |
| SkCanvas* BeginPaintCurrentFrame() override; |
| sk_sp<SkImage> MakePromiseSkImageFromYUV( |
| const std::vector<ImageContext*>& contexts, |
| sk_sp<SkColorSpace> image_color_space, |
| SkYUVAInfo::PlaneConfig plane_config, |
| SkYUVAInfo::Subsampling subsampling) override; |
| void SwapBuffersSkipped(const gfx::Rect root_pass_damage_rect) override; |
| void ScheduleOutputSurfaceAsOverlay( |
| OverlayProcessorInterface::OutputSurfaceOverlayPlane output_surface_plane) |
| override; |
| |
| SkCanvas* BeginPaintRenderPass(const AggregatedRenderPassId& id, |
| const gfx::Size& surface_size, |
| SharedImageFormat format, |
| bool mipmap, |
| bool scanout_dcomp_surface, |
| sk_sp<SkColorSpace> color_space, |
| bool is_overlay, |
| const gpu::Mailbox& mailbox) override; |
| SkCanvas* RecordOverdrawForCurrentPaint() override; |
| void EndPaint( |
| base::OnceClosure on_finished, |
| base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb, |
| const gfx::Rect& update_rect, |
| bool is_overlay) override; |
| void MakePromiseSkImage(ImageContext* image_context, |
| const gfx::ColorSpace& yuv_color_space) override; |
| sk_sp<SkImage> MakePromiseSkImageFromRenderPass( |
| const AggregatedRenderPassId& id, |
| const gfx::Size& size, |
| SharedImageFormat format, |
| bool mipmap, |
| sk_sp<SkColorSpace> color_space, |
| const gpu::Mailbox& mailbox) override; |
| |
| void RemoveRenderPassResource( |
| std::vector<AggregatedRenderPassId> ids) override; |
| void ScheduleOverlays(OverlayList overlays, |
| std::vector<gpu::SyncToken> sync_tokens) override; |
| |
| void CopyOutput(const copy_output::RenderPassGeometry& geometry, |
| const gfx::ColorSpace& color_space, |
| std::unique_ptr<CopyOutputRequest> request, |
| const gpu::Mailbox& mailbox) override; |
| void AddContextLostObserver(ContextLostObserver* observer) override; |
| void RemoveContextLostObserver(ContextLostObserver* observer) override; |
| void PreserveChildSurfaceControls() override; |
| gpu::SyncToken Flush() override; |
| bool EnsureMinNumberOfBuffers(int n) override; |
| gpu::Mailbox CreateSharedImage(SharedImageFormat format, |
| const gfx::Size& size, |
| const gfx::ColorSpace& color_space, |
| uint32_t usage, |
| base::StringPiece debug_label, |
| gpu::SurfaceHandle surface_handle) override; |
| gpu::Mailbox CreateSolidColorSharedImage( |
| const SkColor4f& color, |
| const gfx::ColorSpace& color_space) override; |
| void DestroySharedImage(const gpu::Mailbox& mailbox) override; |
| bool SupportsBGRA() const override; |
| |
| // ExternalUseClient implementation: |
| gpu::SyncToken ReleaseImageContexts( |
| std::vector<std::unique_ptr<ImageContext>> image_contexts) override; |
| std::unique_ptr<ExternalUseClient::ImageContext> CreateImageContext( |
| const gpu::MailboxHolder& holder, |
| const gfx::Size& size, |
| SharedImageFormat format, |
| bool maybe_concurrent_reads, |
| const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info, |
| sk_sp<SkColorSpace> color_space, |
| bool raw_draw_if_possible) override; |
| |
| void InitDelegatedInkPointRendererReceiver( |
| mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> |
| pending_receiver) override; |
| |
| // Set the fields of |capabilities_| and propagates to |impl_on_gpu_|. Should |
| // be called after BindToClient(). |
| void SetCapabilitiesForTesting(gfx::SurfaceOrigin output_surface_origin); |
| |
| // Used in unit tests. |
| void ScheduleGpuTaskForTesting( |
| base::OnceClosure callback, |
| std::vector<gpu::SyncToken> sync_tokens) override; |
| |
| private: |
| bool Initialize(); |
| void InitializeOnGpuThread(GpuVSyncCallback vsync_callback_runner, |
| bool* result); |
| SkSurfaceCharacterization CreateSkSurfaceCharacterizationRenderPass( |
| const gfx::Size& surface_size, |
| SkColorType color_type, |
| SkAlphaType alpha_type, |
| bool mipmap, |
| sk_sp<SkColorSpace> color_space, |
| bool is_overlay, |
| bool scanout_dcomp_surface) const; |
| SkSurfaceCharacterization CreateSkSurfaceCharacterizationCurrentFrame( |
| const gfx::Size& surface_size, |
| SkColorType color_type, |
| SkAlphaType alpha_type, |
| bool mipmap, |
| sk_sp<SkColorSpace> color_space) const; |
| void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params, |
| const gfx::Size& pixel_size, |
| gfx::GpuFenceHandle release_fence); |
| void BufferPresented(const gfx::PresentationFeedback& feedback); |
| void AddChildWindowToBrowser(gpu::SurfaceHandle child_window); |
| |
| // Provided as a callback for the GPU thread. |
| void OnGpuVSync(base::TimeTicks timebase, base::TimeDelta interval); |
| |
| using GpuTask = base::OnceClosure; |
| void EnqueueGpuTask(GpuTask task, |
| std::vector<gpu::SyncToken> sync_tokens, |
| bool make_current, |
| bool need_framebuffer); |
| void ScheduleOrRetainGpuTask(base::OnceClosure callback, |
| std::vector<gpu::SyncToken> tokens); |
| |
| enum class SyncMode { |
| kNoWait = 0, |
| kWaitForTasksStarted = 1, |
| kWaitForTasksFinished = 2, |
| }; |
| void FlushGpuTasks(SyncMode sync_mode); |
| // When flushing the final task to destroy |impl_on_gpu_| we need to pass in a |
| // copy of that pointer for any tasks that were already enqueued and will run |
| // before the destructor. |
| void FlushGpuTasksWithImpl(SyncMode sync_mode, |
| SkiaOutputSurfaceImplOnGpu* impl_on_gpu); |
| GrBackendFormat GetGrBackendFormatForTexture( |
| SharedImageFormat si_format, |
| int plane_index, |
| uint32_t gl_texture_target, |
| const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info); |
| void MakePromiseSkImageSinglePlane(ImageContextImpl* image_context, |
| bool mipmapped); |
| void MakePromiseSkImageMultiPlane(ImageContextImpl* image_context, |
| const gfx::ColorSpace& yuv_color_space); |
| void ContextLost(); |
| void RecreateRootDDLRecorder(); |
| |
| raw_ptr<OutputSurfaceClient> client_ = nullptr; |
| bool needs_swap_size_notifications_ = false; |
| |
| // Images for current frame or render pass. |
| std::vector<ImageContextImpl*> images_in_current_paint_; |
| |
| THREAD_CHECKER(thread_checker_); |
| |
| // Observers for context lost. |
| base::ObserverList<ContextLostObserver>::Unchecked observers_; |
| |
| uint64_t sync_fence_release_ = 0; |
| raw_ptr<SkiaOutputSurfaceDependency> dependency_; |
| UpdateVSyncParametersCallback update_vsync_parameters_callback_; |
| GpuVSyncCallback gpu_vsync_callback_; |
| bool is_displayed_as_overlay_ = false; |
| gpu::Mailbox last_swapped_mailbox_; |
| |
| gfx::Size size_; |
| SharedImageFormat format_; |
| int sample_count_ = 1; |
| SkColorType color_type_ = kUnknown_SkColorType; |
| SkAlphaType alpha_type_ = kUnknown_SkAlphaType; |
| sk_sp<SkColorSpace> sk_color_space_; |
| bool reset_ddl_recorder_on_swap_ = false; |
| absl::optional<SkDeferredDisplayListRecorder> root_ddl_recorder_; |
| |
| class ScopedPaint { |
| public: |
| // Ganesh root surface |
| explicit ScopedPaint(SkDeferredDisplayListRecorder* root_ddl_recorder); |
| // Ganesh render pass (root or non-root) |
| ScopedPaint(const SkSurfaceCharacterization& characterization, |
| const gpu::Mailbox& mailbox); |
| // Graphite (root or non-root) |
| ScopedPaint(skgpu::graphite::Recorder* recorder, |
| const SkImageInfo& image_info, |
| skgpu::graphite::TextureInfo texture_info, |
| const gpu::Mailbox& mailbox = gpu::Mailbox()); |
| ~ScopedPaint(); |
| |
| // SkCanvas for the current paint, retrieved from the DDL recorder for |
| // Ganesh, or from the Graphite recorder. |
| SkCanvas* canvas() const { return canvas_; } |
| |
| // Mailbox for the render pass for the current paint (if present). |
| const gpu::Mailbox& mailbox() const { return mailbox_; } |
| |
| // Detach DDL and reset the SkCanvas pointer. |
| sk_sp<SkDeferredDisplayList> DetachDDL(); |
| |
| // Snap Graphite recording and reset the SkCanvas pointer. |
| std::unique_ptr<skgpu::graphite::Recording> SnapRecording(); |
| |
| private: |
| // This is the DDL recorder being used for current paint when using Ganesh. |
| raw_ptr<SkDeferredDisplayListRecorder> ddl_recorder_ = nullptr; |
| // If we need new recorder for this Paint (i.e. it's not root render pass), |
| // it's stored here |
| absl::optional<SkDeferredDisplayListRecorder> ddl_recorder_storage_; |
| // Graphite recorder used for current paint. |
| raw_ptr<skgpu::graphite::Recorder> graphite_recorder_ = nullptr; |
| // SkCanvas for the current paint, retrieved from the DDL recorder for |
| // Ganesh, or from the Graphite recorder. |
| raw_ptr<SkCanvas> canvas_ = nullptr; |
| // Mailbox for the render pass for the current paint (if present). |
| const gpu::Mailbox mailbox_; |
| }; |
| |
| // Tracks damage across at most `number_of_buffers`. Note this implementation |
| // only assumes buffers are used in a circular order, and does not require a |
| // fixed number of frame buffers to be allocated. |
| class FrameBufferDamageTracker { |
| public: |
| explicit FrameBufferDamageTracker(size_t number_of_buffers); |
| ~FrameBufferDamageTracker(); |
| |
| void FrameBuffersChanged(const gfx::Size& frame_buffer_size); |
| void SwappedWithDamage(const gfx::Rect& damage); |
| void SkippedSwapWithDamage(const gfx::Rect& damage); |
| gfx::Rect GetCurrentFrameBufferDamage() const; |
| |
| private: |
| gfx::Rect ComputeCurrentFrameBufferDamage() const; |
| |
| size_t number_of_buffers_; |
| gfx::Size frame_buffer_size_; |
| // This deque should contains the incremental damage of the last N swapped |
| // frames where N is at most `number_of_buffers_`. Each rect represents |
| // from the incremental damage from the previous frame; note if there is no |
| // previous frame (eg first swap after a `Reshape`), the damage should be |
| // the full frame buffer. |
| base::circular_deque<gfx::Rect> damage_between_frames_; |
| // Result of `GetCurrentFramebufferDamage` to optimize consecutive calls. |
| mutable absl::optional<gfx::Rect> cached_current_damage_; |
| }; |
| |
| // This holds current paint info |
| absl::optional<ScopedPaint> current_paint_; |
| |
| // The SkDDL recorder is used for overdraw feedback. It is created by |
| // BeginPaintOverdraw, and FinishPaintCurrentFrame will turn it into a SkDDL |
| // and play the SkDDL back on the GPU thread. |
| absl::optional<SkDeferredDisplayListRecorder> overdraw_surface_ddl_recorder_; |
| |
| // |overdraw_canvas_| is used to record draw counts. |
| absl::optional<SkOverdrawCanvas> overdraw_canvas_; |
| |
| // |nway_canvas_| contains |overdraw_canvas_| and root canvas. |
| absl::optional<SkNWayCanvas> nway_canvas_; |
| |
| // The cache for promise image created from render passes. |
| base::flat_map<AggregatedRenderPassId, std::unique_ptr<ImageContextImpl>> |
| render_pass_image_cache_; |
| |
| // Sync tokens for resources which are used for the current frame or render |
| // pass. |
| std::vector<gpu::SyncToken> resource_sync_tokens_; |
| |
| const RendererSettings renderer_settings_; |
| |
| // Points to the viz-global singleton. |
| const raw_ptr<const DebugRendererSettings> debug_settings_; |
| |
| // For testing cases we would need to setup a SkiaOutputSurface without |
| // OverlayProcessor and Display. For those cases, we hold the gpu task |
| // scheduler inside this class by having a unique_ptr. |
| // TODO(weiliangc): After changing to proper initialization order for Android |
| // WebView, remove this holder. |
| const raw_ptr<DisplayCompositorMemoryAndTaskController> |
| display_compositor_controller_; |
| |
| // |gpu_task_scheduler_| holds a gpu::SingleTaskSequence, and helps schedule |
| // tasks on GPU as a single sequence. It is shared with OverlayProcessor so |
| // compositing and overlay processing are in order. A gpu::SingleTaskSequence |
| // in regular Viz is implemented by SchedulerSequence. In Android WebView |
| // gpu::SingleTaskSequence is implemented on top of WebView's task queue. |
| const raw_ptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_; |
| |
| // True if raw draw is being used. |
| const bool is_using_raw_draw_; |
| |
| // True if raw draw is using MSAA output surface. |
| const bool is_raw_draw_using_msaa_; |
| |
| // The display transform relative to the hardware natural orientation, |
| // applied to the frame content. The transform can be rotations in 90 degree |
| // increments or flips. |
| gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE; |
| |
| // |impl_on_gpu| is created and destroyed on the GPU thread by a posted task |
| // from SkiaOutputSurfaceImpl::Initialize and SkiaOutputSurfaceImpl::dtor. So |
| // it's safe to use base::Unretained for posting tasks during life time of |
| // SkiaOutputSurfaceImpl. |
| std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_; |
| |
| sk_sp<GrContextThreadSafeProxy> gr_context_thread_safe_; |
| raw_ptr<skgpu::graphite::Recorder> graphite_recorder_ = nullptr; |
| |
| bool has_set_draw_rectangle_for_frame_ = false; |
| absl::optional<gfx::Rect> draw_rectangle_; |
| |
| bool should_measure_next_post_task_ = false; |
| |
| // GPU tasks pending for flush. |
| std::vector<GpuTask> gpu_tasks_; |
| // GPU sync tokens which are depended by |gpu_tasks_|. |
| std::vector<gpu::SyncToken> gpu_task_sync_tokens_; |
| // True if _any_ of |gpu_tasks_| need a GL context. |
| bool make_current_ = false; |
| // True if _any_ of |gpu_tasks_| need to access the framebuffer. |
| bool need_framebuffer_ = false; |
| |
| bool use_damage_area_from_skia_output_device_ = false; |
| // Damage area of the current buffer. Differ to the last submit buffer. |
| absl::optional<gfx::Rect> damage_of_current_buffer_; |
| |
| // Used when `use_damage_area_from_skia_output_device_` is false and keeps |
| // track of across multiple frame buffers. Can be nullptr. |
| absl::optional<FrameBufferDamageTracker> frame_buffer_damage_tracker_; |
| |
| // Track if the current buffer content is changed. |
| bool current_buffer_modified_ = false; |
| |
| // Last number sent to `SetNumberOfFrameBuffers` on the GPU. |
| int cached_number_of_buffers_ = 0; |
| |
| // For accessing tile shared image backings from compositor thread. |
| std::unique_ptr<gpu::SharedImageRepresentationFactory> |
| representation_factory_; |
| // The refresh interval from presentation feedback. |
| base::TimeDelta refresh_interval_; |
| |
| base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr_; |
| base::WeakPtrFactory<SkiaOutputSurfaceImpl> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace viz |
| |
| #endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ |