blob: dfc9bb3fd06b5e97daeb4f6f7b61bee947bce306 [file] [log] [blame]
// Copyright 2014 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_SURFACE_AGGREGATOR_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_SURFACE_AGGREGATOR_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/common/surfaces/surface_range.h"
#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/render_pass_id_remapper.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/overlay_transform.h"
namespace viz {
class AggregatedFrame;
class CompositorFrame;
class DisplayResourceProvider;
class Surface;
class SurfaceClient;
class SurfaceDrawQuad;
class SurfaceManager;
class VIZ_SERVICE_EXPORT SurfaceAggregator {
public:
using SurfaceIndexMap = base::flat_map<SurfaceId, uint64_t>;
using FrameSinkIdMap = base::flat_map<FrameSinkId, LocalSurfaceId>;
// Interface that can modify the aggregated CompositorFrame to annotate it.
// For example it could add extra quads.
class FrameAnnotator {
public:
virtual ~FrameAnnotator() = default;
virtual void AnnotateAggregatedFrame(AggregatedFrame* frame) = 0;
};
SurfaceAggregator(SurfaceManager* manager,
DisplayResourceProvider* provider,
bool aggregate_only_damaged,
bool needs_surface_damage_rect_list);
~SurfaceAggregator();
// |target_damage| represents an area on the output surface that might have
// been invalidated. It can be used in cases where we still want to support
// partial damage but the target surface might need contents outside the
// damage rect of the root surface.
AggregatedFrame Aggregate(const SurfaceId& surface_id,
base::TimeTicks expected_display_time,
gfx::OverlayTransform display_transform,
const gfx::Rect& target_damage = gfx::Rect(),
int64_t display_trace_id = -1);
void ReleaseResources(const SurfaceId& surface_id);
const SurfaceIndexMap& previous_contained_surfaces() const {
return previous_contained_surfaces_;
}
const FrameSinkIdMap& previous_contained_frame_sinks() const {
return previous_contained_frame_sinks_;
}
void SetFullDamageForSurface(const SurfaceId& surface_id);
void set_output_is_secure(bool secure) { output_is_secure_ = secure; }
// Only used with experimental de-jelly effect.
bool last_frame_had_jelly() const { return last_frame_had_jelly_; }
// Set the color spaces for the created RenderPasses, which is propagated
// to the output surface.
void SetDisplayColorSpaces(const gfx::DisplayColorSpaces& color_spaces);
void SetMaxRenderTargetSize(int max_size);
bool NotifySurfaceDamageAndCheckForDisplayDamage(const SurfaceId& surface_id);
bool HasFrameAnnotator() const;
void SetFrameAnnotator(std::unique_ptr<FrameAnnotator> frame_annotator);
void DestroyFrameAnnotator();
private:
struct PrewalkResult;
struct ChildSurfaceInfo;
struct RenderPassMapEntry;
struct MaskFilterInfoExt;
struct AggregateStatistics {
int prewalked_surface_count = 0;
int copied_surface_count = 0;
int declare_resources_count = 0;
base::TimeDelta prewalk_time;
base::TimeDelta copy_time;
base::TimeDelta declare_resources_time;
};
// Helper function that gets a list of render passes and returns a map from
// render pass ids to render passes.
static base::flat_map<CompositorRenderPassId, RenderPassMapEntry>
GenerateRenderPassMap(const CompositorRenderPassList& render_pass_list,
bool is_root_surface);
absl::optional<gfx::Rect> CalculateClipRect(
const absl::optional<gfx::Rect>& surface_clip,
const absl::optional<gfx::Rect>& quad_clip,
const gfx::Transform& target_transform);
void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
float parent_device_scale_factor,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
AggregatedRenderPass* dest_pass,
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
const MaskFilterInfoExt& mask_filter_info_pair);
void EmitSurfaceContent(Surface* surface,
float parent_device_scale_factor,
const SurfaceDrawQuad* surface_quad,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
AggregatedRenderPass* dest_pass,
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
const MaskFilterInfoExt& mask_filter_info_pair);
void EmitDefaultBackgroundColorQuad(
const SurfaceDrawQuad* surface_quad,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
AggregatedRenderPass* dest_pass,
const MaskFilterInfoExt& mask_filter_info_pair);
void EmitGutterQuadsIfNecessary(
const gfx::Rect& primary_rect,
const gfx::Rect& fallback_rect,
const SharedQuadState* primary_shared_quad_state,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
SkColor background_color,
AggregatedRenderPass* dest_pass,
const MaskFilterInfoExt& mask_filter_info_pair);
SharedQuadState* CopySharedQuadState(
const SharedQuadState* source_sqs,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
AggregatedRenderPass* dest_render_pass,
const MaskFilterInfoExt& mask_filter_info_pair);
SharedQuadState* CopyAndScaleSharedQuadState(
const SharedQuadState* source_sqs,
const gfx::Transform& scaled_quad_to_target_transform,
const gfx::Transform& target_transform,
const gfx::Rect& quad_layer_rect,
const gfx::Rect& visible_quad_layer_rect,
const absl::optional<gfx::Rect>& clip_rect,
AggregatedRenderPass* dest_render_pass,
const MaskFilterInfoExt& mask_filter_info_pair);
void CopyQuadsToPass(
const CompositorRenderPass& source_pass,
AggregatedRenderPass* dest_pass,
float parent_device_scale_factor,
const std::unordered_map<ResourceId, ResourceId, ResourceIdHasher>&
resource_to_child_map,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
const Surface* surface,
const MaskFilterInfoExt& mask_filter_info_pair);
// Recursively walks through the render pass and updates the
// |intersects_damage_under| flag on all RenderPassDrawQuads(RPDQ).
// The function returns the damage rect of the render pass in its own content
// space.
// - |render_pass_entry| specifies the render pass in the entry map to be
// prewalked
// - |surface| is the surface containing the render pass.
// - |render_pass_map| is a map that contains all render passes and their
// entry data.
// - |will_draw| indicates that the surface can be aggregated into the final
// frame and might be drawn (based on damage/occlusion/etc.) if it is set
// to true. Or the surface isn't in the aggregated frame and is only
// needed for CopyOutputRequests if set to false.
// - |damage_from_parent| is the damage rect passed along from parent or
// a chain of ancestor render passes, transformed into the local space of
// the current render pass. This happens when the root render
// pass of |surface| is merged to its parent render pass (and so on).
// |damage_from_parent| represents the current effective accumulated damage
// from the parent render pass into which the surface quad containing the
// |surface| is being merged. This includes the damage from quads under
// the surface quad in the render pass merged to, plus its |damage_rect|
// and damage passed onto it by its parent if any.
// If there's no merging of |surface|, |accummulated_damage| is empty.
// - |target_to_root_transform| is the transform from current render pass to
// the root.
// - |in_moved_pixel_rp| marks if the current render pass is embedded by an
// ancestor render pass with a pixel-moving foreground filter.
// - |result| is the result of a prewalk of the surface that contains the
// render pass.
gfx::Rect PrewalkRenderPass(
RenderPassMapEntry* render_pass_entry,
const Surface* surface,
base::flat_map<CompositorRenderPassId, RenderPassMapEntry>*
render_pass_map,
bool will_draw,
const gfx::Rect& damage_from_parent,
const gfx::Transform& target_to_root_transform,
bool in_moved_pixel_rp,
PrewalkResult* result);
// Walk the Surface tree from |surface|. Validate the resources of the
// current surface and its descendants, check if there are any copy requests,
// and return the combined damage rect.
gfx::Rect PrewalkSurface(Surface* surface,
bool in_moved_pixel_rp,
AggregatedRenderPassId parent_pass,
bool will_draw,
const gfx::Rect& damage_from_parent,
PrewalkResult* result);
// Declares all of the resources to the resource provider. Also declares
// resources that are used in the render_pass_list. Returns true if this seems
// to be a valid frame (all resources used in the render pass are present in
// the resource list).
bool DeclareResourcesToProvider(
Surface* surface,
const std::vector<TransferableResource>& resource_list,
const CompositorRenderPassList& render_pass_list);
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
void CopyPasses(const CompositorFrame& frame, Surface* surface);
void AddColorConversionPass();
void AddDisplayTransformPass();
// Remove Surfaces that were referenced before but aren't currently
// referenced from the ResourceProvider.
// Also notifies SurfaceAggregatorClient of newly added and removed
// child surfaces.
void ProcessAddedAndRemovedSurfaces();
void PropagateCopyRequestPasses();
bool CheckFrameSinksChanged(const Surface* surface);
// Returns true if the quad list from the render pass provided can be merged
// with its target render pass based on mask filter info.
bool CanMergeMaskFilterInfo(const MaskFilterInfoExt& mask_filter_info_pair,
const CompositorRenderPass& root_render_pass);
int ChildIdForSurface(Surface* surface);
bool IsSurfaceFrameIndexSameAsPrevious(const Surface* surface) const;
gfx::Rect DamageRectForSurface(const Surface* surface,
const CompositorRenderPass& source) const;
// This function adds |damage_rect| to
// |damage_rects_union_of_surfaces_on_top_|. |damage_rect| is in the quad
// content space while both clip_rect and
// |damage_rects_union_of_surfaces_on_top_| are already on the root target
// space.
void AddSurfaceDamageToDamageList(
const gfx::Rect& damage_rect,
const gfx::Transform& parent_target_transform,
const absl::optional<gfx::Rect>& clip_rect,
const CompositorRenderPass* source_pass,
AggregatedRenderPass* dest_pass,
Surface* surface);
void AddRenderPassFilterDamageToDamageList(
const gfx::Transform& parent_target_transform,
const CompositorRenderPass* source_pass,
AggregatedRenderPass* dest_pass);
// Determine the overlay damage and location in the surface damage list.
const DrawQuad* FindQuadWithOverlayDamage(
const CompositorRenderPass& source_pass,
AggregatedRenderPass* dest_pass,
const gfx::Transform& parent_target_transform,
const Surface* surface,
const absl::optional<gfx::Rect>& clip_rect,
size_t* overlay_damage_index);
// Returns true if the render pass with the given id and cache_render_pass
// flag would need full damage.
bool RenderPassNeedsFullDamage(const AggregatedRenderPassId& id,
bool cache_render_pass) const;
bool IsRootSurface(const Surface* surface) const;
static void UnrefResources(base::WeakPtr<SurfaceClient> surface_client,
std::vector<ReturnedResource> resources);
// This method transforms the delegated ink metadata to be in the root target
// space, so that it can eventually be drawn onto the back buffer in the
// correct position. It should only ever be called when a frame contains
// delegated ink metadata, in which case this function will transform it and
// then store it in the |delegated_ink_metadata_| member.
void TransformAndStoreDelegatedInkMetadata(
const gfx::Transform& parent_quad_to_root_target_transform,
std::unique_ptr<gfx::DelegatedInkMetadata> metadata);
// Preliminary check to see if a surface contained in |surface_quad| can
// potentially merge its root render pass. If so, returns true.
static bool CanPotentiallyMergePass(const SurfaceDrawQuad& surface_quad);
// De-Jelly Effect:
// HandleDeJelly applies a de-jelly transform to quads in the root render
// pass.
void HandleDeJelly(Surface* surface);
// CreateDeJellyRenderPassQuads promotes skewed quads from the root render
// pass into |render_pass|. Skew is applied when |render_pass| is drawn.
void CreateDeJellyRenderPassQuads(
cc::ListContainer<DrawQuad>::Iterator* quad_iterator,
const cc::ListContainer<DrawQuad>::Iterator& end,
const gfx::Rect& jelly_clip,
float skew,
AggregatedRenderPass* render_pass);
// Appends quads directly to |root_pass|, applying |skew|.
void CreateDeJellyNormalQuads(
cc::ListContainer<DrawQuad>::Iterator* quad_iterator,
const cc::ListContainer<DrawQuad>::Iterator& end,
AggregatedRenderPass* root_pass,
float skew);
// Appends |render_pass| to |root_pass|, applying |skew|, |jelly_clip|,
// |opacity|, and |blend_mode|.
void AppendDeJellyRenderPass(
float skew,
const gfx::Rect& jelly_clip,
float opacity,
SkBlendMode blend_mode,
AggregatedRenderPass* root_pass,
std::unique_ptr<AggregatedRenderPass> render_pass);
// Appends quads from |quad_iterator| to |render_pass| for |state|.
void AppendDeJellyQuadsForSharedQuadState(
cc::ListContainer<DrawQuad>::Iterator* quad_iterator,
const cc::ListContainer<DrawQuad>::Iterator& end,
AggregatedRenderPass* render_pass,
const SharedQuadState* state);
// Update |last_frame_had_jelly_|, should be called once per frame.
void SetLastFrameHadJelly(bool had_jelly);
// Records UMA histograms and resets |stats_|.
void RecordStatHistograms();
// Resets member variables that were used during Aggregate().
void ResetAfterAggregate();
SurfaceManager* const manager_;
DisplayResourceProvider* const provider_;
const bool aggregate_only_damaged_;
// If true, per-surface damage rect list will be produced.
const bool needs_surface_damage_rect_list_;
// Whether de-jelly may be active.
const bool de_jelly_enabled_;
bool output_is_secure_ = false;
// The color space for the root render pass. If this is different from its
// blending color space (e.g. for HDR), then a final render pass to convert
// between the two will be added. This space must always be valid.
gfx::DisplayColorSpaces display_color_spaces_;
// Maximum texture size which if larger than zero, will limit the size of
// render passes.
int max_render_target_size_ = 0;
// The id for the final color conversion render pass.
AggregatedRenderPassId color_conversion_render_pass_id_;
// The id for the optional render pass used to apply the display transform.
AggregatedRenderPassId display_transform_render_pass_id_;
base::flat_map<SurfaceId, int> surface_id_to_resource_child_id_;
// The following state is only valid for the duration of one Aggregate call
// and is only stored on the class to avoid having to pass through every
// function call.
// This is the set of surfaces referenced in the aggregation so far, used to
// detect cycles.
base::flat_set<SurfaceId> referenced_surfaces_;
SurfaceId root_surface_id_;
gfx::Transform root_surface_transform_;
absl::optional<AggregateStatistics> stats_;
// For each Surface used in the last aggregation, gives the frame_index at
// that time.
SurfaceIndexMap previous_contained_surfaces_;
SurfaceIndexMap contained_surfaces_;
FrameSinkIdMap previous_contained_frame_sinks_;
FrameSinkIdMap contained_frame_sinks_;
// After surface validation, every Surface in this set is valid.
base::flat_set<SurfaceId> valid_surfaces_;
// This is the pass list for the aggregated frame.
AggregatedRenderPassList* dest_pass_list_ = nullptr;
// The target display time for the aggregated frame.
base::TimeTicks expected_display_time_;
// This is the set of aggregated pass ids that are affected by filters that
// move pixels.
base::flat_set<AggregatedRenderPassId> moved_pixel_passes_;
// This is the set of aggregated pass ids that are drawn by copy requests, so
// should not have their damage rects clipped to the root damage rect.
base::flat_set<AggregatedRenderPassId> copy_request_passes_;
// This is the set of aggregated pass ids that has damage from contributing
// content.
base::flat_set<AggregatedRenderPassId> contributing_content_damaged_passes_;
// This maps each aggregated pass id to the set of (aggregated) pass ids
// that its RenderPassDrawQuads depend on
base::flat_map<AggregatedRenderPassId, base::flat_set<AggregatedRenderPassId>>
render_pass_dependencies_;
// The root damage rect of the currently-aggregating frame.
gfx::Rect root_damage_rect_;
// A pointer to the list of surface damage rects from the current
// AggregatedFrame, used for overlay optimization.
SurfaceDamageRectList* surface_damage_rect_list_;
// The aggregate color content usage of the currently-aggregating frame. This
// is computed by the prewalk, and is used to determine the format and color
// space of all render passes. Note that that is more heavy-handed than is
// desirable.
gfx::ContentColorUsage root_content_color_usage_ =
gfx::ContentColorUsage::kSRGB;
// True if the frame that's currently being aggregated has copy requests.
// This is valid during Aggregate after PrewalkSurface is called.
bool has_copy_requests_ = false;
// True if the frame that's currently being aggregated has cached render
// passes. This is valid during Aggregate after PrewalkSurface is called.
bool has_cached_render_passes_ = false;
// True if any RenderPasses in the aggregated frame have a backdrop filter
// that moves pixels. This is valid during Aggregate after PrewalkSurface is
// called.
bool has_pixel_moving_backdrop_filter_ = false;
// For each FrameSinkId, contains a vector of SurfaceRanges that will damage
// the display if they're damaged.
base::flat_map<FrameSinkId, std::vector<SurfaceRange>> damage_ranges_;
// Used to annotate the aggregated frame for debugging.
std::unique_ptr<FrameAnnotator> frame_annotator_;
int64_t display_trace_id_ = -1;
base::flat_set<SurfaceId> undrawn_surfaces_;
// Variables used for de-jelly:
// The set of surfacees being drawn for the first time. Used to determine if
// de-jelly skew should be applied to a surface.
base::flat_set<SurfaceId> new_surfaces_;
// Whether the last drawn frame had de-jelly skew applied. Used in production
// on Android only.
bool last_frame_had_jelly_ = false;
// Whether the last drawn frame had a color conversion pass applied. Used in
// production on Windows only (does not interact with jelly).
bool last_frame_had_color_conversion_pass_ = false;
// The metadata used for drawing a delegated ink trail on the end of a normal
// ink stroke. It needs to be transformed to root coordinates and then put on
// the final aggregated frame. This is only populated during aggregation when
// a surface contains delegated ink metadata on its frame, and it is cleared
// after it is placed on the final aggregated frame during aggregation.
std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata_;
// Whether the last aggregated frame contained delegated ink metadata or not.
// Used to determine if the root render pass needs to remain expanded by the
// target damage or not, because that allows a frame to be drawn after inking
// is finished to remove the last drawn ink trail.
bool last_frame_had_delegated_ink_ = false;
// The current surface has zero_damage_rect and is not recorded in
// surface_damage_rect_list_ . Set by AddSurfaceDamageToDamageList() and read
// by FindQuadWithOverlayDamage().
bool current_zero_damage_rect_is_not_recorded_ = false;
// Indicates whether video capture has been enabled for this frame.
bool video_capture_enabled_ = false;
// A helper class used to remap render pass IDs from the surface namespace to
// a common space, to avoid collisions.
RenderPassIdRemapper pass_id_remapper_;
base::WeakPtrFactory<SurfaceAggregator> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SURFACE_AGGREGATOR_H_