blob: 80edfe380f3f90229b909cc048c9790fe5c5418a [file] [log] [blame]
// Copyright 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 COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "cc/cc_export.h"
#include "components/viz/service/display/direct_renderer.h"
#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/color_conversion_sk_filter_cache.h"
#include "ui/gfx/geometry/mask_filter_info.h"
#include "ui/latency/latency_info.h"
class SkColorFilter;
namespace viz {
class AggregatedRenderPassDrawQuad;
class DebugBorderDrawQuad;
class DelegatedInkPointRendererBase;
class DelegatedInkHandler;
class PictureDrawQuad;
class SkiaOutputSurface;
class SolidColorDrawQuad;
class TextureDrawQuad;
class TileDrawQuad;
class YUVVideoDrawQuad;
// TODO(795132): SkColorSpace is only a subset comparing to gfx::ColorSpace.
// Need to figure out support for color space that is not covered by
// SkColorSpace.
class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
public:
// TODO(penghuang): Remove skia_output_surface when DDL is used everywhere.
SkiaRenderer(const RendererSettings* settings,
const DebugRendererSettings* debug_settings,
OutputSurface* output_surface,
DisplayResourceProviderSkia* resource_provider,
OverlayProcessorInterface* overlay_processor,
SkiaOutputSurface* skia_output_surface);
SkiaRenderer(const SkiaRenderer&) = delete;
SkiaRenderer& operator=(const SkiaRenderer&) = delete;
~SkiaRenderer() override;
void SwapBuffers(SwapFrameData swap_frame_data) override;
void SwapBuffersSkipped() override;
void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) override;
void BuffersPresented() override;
void DidReceiveReleasedOverlays(
const std::vector<gpu::Mailbox>& released_overlays) override;
void SetDisablePictureQuadImageFiltering(bool disable) {
disable_picture_quad_image_filtering_ = disable;
}
DelegatedInkPointRendererBase* GetDelegatedInkPointRenderer(
bool create_if_necessary) override;
void SetDelegatedInkMetadata(
std::unique_ptr<gfx::DelegatedInkMetadata> metadata) override;
gfx::Rect GetCurrentFramebufferDamage() const override;
void Reshape(const OutputSurface::ReshapeParams& reshape_params) override;
void EnsureMinNumberOfBuffers(int n) override;
protected:
bool CanPartialSwap() override;
void UpdateRenderPassTextures(
const AggregatedRenderPassList& render_passes_in_draw_order,
const base::flat_map<AggregatedRenderPassId, RenderPassRequirements>&
render_passes_in_frame) override;
void AllocateRenderPassResourceIfNeeded(
const AggregatedRenderPassId& render_pass_id,
const RenderPassRequirements& requirements) override;
bool IsRenderPassResourceAllocated(
const AggregatedRenderPassId& render_pass_id) const override;
gfx::Size GetRenderPassBackingPixelSize(
const AggregatedRenderPassId& render_pass_id) override;
void BindFramebufferToOutputSurface() override;
void BindFramebufferToTexture(
const AggregatedRenderPassId render_pass_id) override;
void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
const gfx::Rect& render_pass_scissor) override;
void DoDrawQuad(const DrawQuad* quad, const gfx::QuadF* draw_region) override;
void BeginDrawingFrame() override;
void FinishDrawingFrame() override;
bool FlippedFramebuffer() const override;
void EnsureScissorTestEnabled() override;
void EnsureScissorTestDisabled() override;
void CopyDrawnRenderPass(const copy_output::RenderPassGeometry& geometry,
std::unique_ptr<CopyOutputRequest> request) override;
void DidChangeVisibility() override;
void FinishDrawingQuadList() override;
void GenerateMipmap() override;
void SetDelegatedInkPointRendererSkiaForTest(
std::unique_ptr<DelegatedInkPointRendererSkia> renderer) override;
std::unique_ptr<DelegatedInkHandler> delegated_ink_handler_;
private:
enum class BypassMode;
struct DrawQuadParams;
struct DrawRPDQParams;
class ScopedSkImageBuilder;
class ScopedYUVSkImageBuilder;
void ClearCanvas(SkColor4f color);
void ClearFramebuffer();
// Callers should init an SkAutoCanvasRestore before calling this function.
// |scissor_rect| and |mask_filter_info| should be in device space,
// i.e. same space that |cdt| will transform subsequent draws into.
void PrepareCanvas(
const absl::optional<gfx::Rect>& scissor_rect,
const absl::optional<gfx::MaskFilterInfo>& mask_filter_info,
const gfx::Transform* cdt);
void PrepareGradient(
const absl::optional<gfx::MaskFilterInfo>& mask_filter_info);
// Further modify the canvas as needed to apply the effects represented by
// |rpdq_params|. Call Prepare[Paint|Color]OrCanvasForRPDQ when possible,
// in order apply the RPDQ effects into a more efficient format.
void PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
DrawQuadParams* params);
// Attempt to apply the effects in |rpdq_params| to the paint used to draw
// the quad; otherwise modify the current canvas instead.
void PreparePaintOrCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
DrawQuadParams* params,
SkPaint* paint);
// Attempt to apply the effects in |rpdq_params| to the color used to draw
// the quad; otherwise modify the current canvas as a fallback.
void PrepareColorOrCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
DrawQuadParams* params,
SkColor4f* color);
// The returned DrawQuadParams can be modified by the DrawX calls that accept
// params so that they can apply explicit data transforms before sending to
// Skia in a consistent manner.
DrawQuadParams CalculateDrawQuadParams(const gfx::Transform& target_to_device,
const gfx::Rect* scissor_rect,
const DrawQuad* quad,
const gfx::QuadF* draw_region) const;
DrawRPDQParams CalculateRPDQParams(const AggregatedRenderPassDrawQuad* quad,
DrawQuadParams* params);
// Modifies |params| and |rpdq_params| to apply correctly when drawing the
// RenderPass directly via |bypass_quad|.
BypassMode CalculateBypassParams(const DrawQuad* bypass_quad,
DrawRPDQParams* rpdq_params,
DrawQuadParams* params) const;
SkCanvas::ImageSetEntry MakeEntry(const SkImage* image,
int matrix_index,
const DrawQuadParams& params) const;
// Returns overall constraint to pass to Skia, and modifies |params| to
// emulate content area clamping different from the provided texture coords.
SkCanvas::SrcRectConstraint ResolveTextureConstraints(
const SkImage* image,
const gfx::RectF& valid_texel_bounds,
DrawQuadParams* params) const;
bool MustFlushBatchedQuads(const DrawQuad* new_quad,
const DrawRPDQParams* rpdq_params,
const DrawQuadParams& params) const;
void AddQuadToBatch(const SkImage* image,
const gfx::RectF& valid_texel_bounds,
DrawQuadParams* params);
void FlushBatchedQuads();
// Utility function that calls appropriate draw function based on quad
// material. If |rpdq_params| is not null, then |quad| is assumed to be the
// bypass quad associated with the RenderPass that defined the |rpdq_params|.
void DrawQuadInternal(const DrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
// Utility to draw a single quad as a filled color, and optionally apply the
// effects defined in |rpdq_params| when the quad is bypassing the render pass
void DrawColoredQuad(SkColor4f color,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
// Utility to make a single ImageSetEntry and draw it with the complex paint,
// and optionally apply the effects defined in |rpdq_params| when the quad is
// bypassing the render pass
void DrawSingleImage(const SkImage* image,
const gfx::RectF& valid_texel_bounds,
const DrawRPDQParams* rpdq_params,
SkPaint* paint,
DrawQuadParams* params);
void DrawPaintOpBuffer(const cc::PaintOpBuffer* buffer,
const absl::optional<SkColor4f>& clear_color,
const TileDrawQuad* quad,
const DrawQuadParams* params);
// RPDQ, DebugBorder and picture quads cannot be batched. They
// either are not textures (debug, picture), or it's very likely
// the texture will have advanced paint effects (rpdq). Additionally, they do
// not support being drawn directly for a pass-through RenderPass.
void DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quad,
DrawQuadParams* params);
void DrawDebugBorderQuad(const DebugBorderDrawQuad* quad,
DrawQuadParams* params);
void DrawPictureQuad(const PictureDrawQuad* quad, DrawQuadParams* params);
// Solid-color quads are not batchable, but can be drawn directly in place of
// a RenderPass (hence it takes the optional DrawRPDQParams).
void DrawSolidColorQuad(const SolidColorDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
void DrawTextureQuad(const TextureDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
void DrawTileDrawQuad(const TileDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
void DrawUnsupportedQuad(const DrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params);
// Schedule overlay candidates for presentation at next SwapBuffers().
void ScheduleOverlays();
// skia_renderer can draw most single-quad passes directly, regardless of
// blend mode or image filtering.
const DrawQuad* CanPassBeDrawnDirectly(
const AggregatedRenderPass* pass) override;
void DrawDelegatedInkTrail() override;
// Get a color filter that converts from |src| color space to |dst| color
// space using a shader constructed from gfx::ColorTransform. The color
// filters are cached in |color_filter_cache_|. Resource offset and
// multiplier are used to adjust the RGB output of the shader for YUV video
// quads. The default values perform no adjustment.
sk_sp<SkColorFilter> GetColorSpaceConversionFilter(
const gfx::ColorSpace& src,
absl::optional<gfx::HDRMetadata> src_hdr_metadata,
const gfx::ColorSpace& dst,
float resource_offset = 0.0f,
float resource_multiplier = 1.0f);
// Returns the color filter that should be applied to the current canvas.
sk_sp<SkColorFilter> GetContentColorFilter();
// Flush SkiaOutputSurface, so all pending GPU tasks in SkiaOutputSurface will
// be sent to GPU scheduler.
void FlushOutputSurface();
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
void PrepareRenderPassOverlay(
OverlayProcessorInterface::PlatformOverlayCandidate* overlay);
#endif
// Sets up callbacks for frame resource fences and passes them to
// SkiaOutputSurface by calling EndPaint on that. If |failed|,
// SkiaOutputSurface::EndPaint will be called with null callbacks.
void EndPaint(bool failed);
DisplayResourceProviderSkia* resource_provider() {
return static_cast<DisplayResourceProviderSkia*>(resource_provider_);
}
// A map from RenderPass id to the texture used to draw the RenderPass from.
struct RenderPassBacking {
gfx::Size size;
bool generate_mipmap;
gfx::ColorSpace color_space;
ResourceFormat format;
gpu::Mailbox mailbox;
bool is_root;
};
base::flat_map<AggregatedRenderPassId, RenderPassBacking>
render_pass_backings_;
sk_sp<SkColorSpace> RenderPassBackingSkColorSpace(
const RenderPassBacking& backing) {
return backing.color_space.ToSkColorSpace(CurrentFrameSDRWhiteLevel());
}
// Interface used for drawing. Common among different draw modes.
raw_ptr<SkCanvas, DanglingUntriaged> current_canvas_ = nullptr;
class FrameResourceGpuCommandsCompletedFence;
scoped_refptr<FrameResourceGpuCommandsCompletedFence>
current_gpu_commands_completed_fence_;
class FrameResourceReleaseFence;
scoped_refptr<FrameResourceReleaseFence> current_release_fence_;
bool disable_picture_quad_image_filtering_ = false;
bool is_scissor_enabled_ = false;
gfx::Rect scissor_rect_;
gfx::Rect swap_buffer_rect_;
// State common to all quads in a batch. Draws that require an SkPaint not
// captured by this state cannot be batched.
struct BatchedQuadState {
absl::optional<gfx::Rect> scissor_rect;
absl::optional<gfx::MaskFilterInfo> mask_filter_info;
SkBlendMode blend_mode;
SkSamplingOptions sampling;
SkCanvas::SrcRectConstraint constraint;
BatchedQuadState();
};
BatchedQuadState batched_quad_state_;
std::vector<SkCanvas::ImageSetEntry> batched_quads_;
// Same order as batched_quads_, but only includes draw regions for the
// entries that have fHasClip == true. Each draw region is 4 consecutive pts
std::vector<SkPoint> batched_draw_regions_;
// Each entry of batched_quads_ will have an index into this vector; multiple
// entries may point to the same matrix.
std::vector<SkMatrix> batched_cdt_matrices_;
// Specific for SkDDL.
const raw_ptr<SkiaOutputSurface, DanglingUntriaged> skia_output_surface_;
const bool is_using_raw_draw_;
// Lock set for resources that are used for the current frame. All resources
// in this set will be unlocked with a sync token when the frame is done in
// the compositor thread. And the sync token will be released when the DDL
// for the current frame is replayed on the GPU thread.
// It is only used with DDL.
absl::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
lock_set_for_external_use_;
struct OverlayLock {
OverlayLock(DisplayResourceProvider* resource_provider,
ResourceId resource_id);
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
explicit OverlayLock(gpu::Mailbox mailbox);
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
~OverlayLock();
OverlayLock(OverlayLock&& other);
OverlayLock& operator=(OverlayLock&& other);
OverlayLock(const OverlayLock&) = delete;
OverlayLock& operator=(const OverlayLock&) = delete;
const gpu::Mailbox& mailbox() const {
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
if (render_pass_lock.has_value()) {
return *render_pass_lock;
}
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
DCHECK(resource_lock.has_value());
return resource_lock->mailbox();
}
const gpu::SyncToken& sync_token() const {
DCHECK(resource_lock.has_value());
return resource_lock->sync_token();
}
void SetReleaseFence(gfx::GpuFenceHandle release_fence) {
if (resource_lock.has_value()) {
resource_lock->SetReleaseFence(std::move(release_fence));
}
}
bool HasReadLockFence() {
if (resource_lock.has_value()) {
return resource_lock->HasReadLockFence();
}
return false;
}
// Either resource_lock is set for non render pass overlays (i.e. videos),
// or render_pass_lock is set for render pass overlays.
absl::optional<DisplayResourceProviderSkia::ScopedReadLockSharedImage>
resource_lock;
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
absl::optional<gpu::Mailbox> render_pass_lock;
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
};
// Locks for overlays that are pending for SwapBuffers().
base::circular_deque<std::vector<OverlayLock>> pending_overlay_locks_;
// Locks for overlays that have been committed. |pending_overlay_locks_| will
// be moved to |committed_overlay_locks_| after SwapBuffers() is completed.
std::vector<OverlayLock> committed_overlay_locks_;
// Locks for overlays that have release fences and read lock fences.
base::circular_deque<std::vector<OverlayLock>>
read_lock_release_fence_overlay_locks_;
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
class OverlayLockComparator {
public:
using is_transparent = void;
bool operator()(const OverlayLock& lhs, const OverlayLock& rhs) const;
};
// A set for locks of overlays which are waiting to be released, using
// mailbox() as the unique key.
base::flat_set<OverlayLock, OverlayLockComparator>
awaiting_release_overlay_locks_;
// Tracks render pass overlay backings that are currently in use and available
// for re-using via mailboxes. RenderPassBacking.generate_mipmap is not used.
std::vector<RenderPassBacking> in_flight_render_pass_overlay_backings_;
std::vector<RenderPassBacking> available_render_pass_overlay_backings_;
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
gfx::ColorConversionSkFilterCache color_filter_cache_;
bool UsingSkiaForDelegatedInk() const;
uint32_t debug_tint_modulate_count_ = 0;
bool use_real_color_space_for_stream_video_ = false;
// Used to get mailboxes for the root render pass when
// capabilities().renderer_allocates_images = true.
std::unique_ptr<BufferQueue> buffer_queue_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_