| // Copyright 2021 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_RESOLVED_FRAME_DATA_H_ |
| #define COMPONENTS_VIZ_SERVICE_DISPLAY_RESOLVED_FRAME_DATA_H_ |
| |
| #include <memory> |
| #include <unordered_map> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/functional/function_ref.h" |
| #include "base/memory/raw_ptr.h" |
| #include "components/viz/common/quads/aggregated_render_pass.h" |
| #include "components/viz/common/quads/compositor_frame_metadata.h" |
| #include "components/viz/common/quads/compositor_render_pass.h" |
| #include "components/viz/common/quads/draw_quad.h" |
| #include "components/viz/common/quads/offset_tag.h" |
| #include "components/viz/common/resources/resource_id.h" |
| #include "components/viz/common/surfaces/surface_id.h" |
| #include "components/viz/service/display/display_resource_provider.h" |
| #include "components/viz/service/surfaces/frame_index_constants.h" |
| #include "components/viz/service/viz_service_export.h" |
| |
| namespace viz { |
| |
| class Surface; |
| |
| // Returns |damage_rect| field from the DrawQuad if it exists otherwise returns |
| // an empty optional. |
| const std::optional<gfx::Rect>& GetOptionalDamageRectFromQuad( |
| const DrawQuad* quad); |
| |
| // Data associated with a DrawQuad in a resolved frame. |
| struct VIZ_SERVICE_EXPORT ResolvedQuadData { |
| explicit ResolvedQuadData(const DrawQuad& quad); |
| |
| // Remapped display ResourceId. |
| ResourceId remapped_resource_id; |
| }; |
| |
| // Render pass data that is fixed for the lifetime of ResolvedPassData. |
| struct VIZ_SERVICE_EXPORT FixedPassData { |
| FixedPassData(); |
| FixedPassData(FixedPassData&& other); |
| FixedPassData& operator=(FixedPassData&& other); |
| ~FixedPassData(); |
| |
| // Only valid during aggregation: set at the beginning a new round of |
| // aggregation and reset to null at the end of each aggregation. |
| // |
| // This shouldn't be dangling anymore because CompositorFrames are never |
| // destroyed during aggregation so the pointer will remain valid for the |
| // duration of aggregation (until it's set to null). |
| raw_ptr<CompositorRenderPass> render_pass = nullptr; |
| |
| // How many times this render pass is embedded by another render pass in the |
| // same frame. |
| int embed_count = 0; |
| |
| AggregatedRenderPassId remapped_id; |
| CompositorRenderPassId render_pass_id; |
| bool is_root = false; |
| std::vector<ResolvedQuadData> draw_quads; |
| }; |
| |
| class ResolvedPassData; |
| |
| // Render pass data that must be recomputed each aggregation. Unlike |
| // FixedPassData this changes each aggregation depending on what other |
| // Surfaces/CompositorFrames are part of the draw tree. |
| struct VIZ_SERVICE_EXPORT AggregationPassData { |
| AggregationPassData(); |
| AggregationPassData(AggregationPassData&& other); |
| AggregationPassData& operator=(AggregationPassData&& other); |
| ~AggregationPassData(); |
| |
| // Resets to default constructed state. |
| void Reset(); |
| |
| // Embedded render passes that contribute pixels to this render pass. |
| base::flat_set<raw_ptr<ResolvedPassData, CtnExperimental>> embedded_passes; |
| |
| // True if the render pass is drawn to fulfil part of a copy request. This |
| // property is transitive from parent pass to embedded passes. |
| bool in_copy_request_pass = false; |
| |
| // True if the render pass is be impacted by a pixel moving foreground filter. |
| // This property is transitive from parent pass to embedded passes. |
| bool in_pixel_moving_filter_pass = false; |
| |
| // True if the render pass will be stored as part of a cached render pass. |
| // This property is transitive from parent pass to embedded passes. |
| bool in_cached_render_pass = false; |
| |
| // True if there is accumulated damage in the render pass or from contributing |
| // render passes or surfaces. This bit indicates whether the render pass needs |
| // to be redrawn since its content has changed from the previous frame or if |
| // the cached content from the previous frame can be reused. |
| // |
| // Note: This is different than checking render pass damage_rect.IsEmpty(). cc |
| // resets any non-root render pass damage_rects and aggregates non-root damage |
| // into the root render pass damage_rect. cc already plumbs a separate bool |
| // `has_damage_from_contributing_content` with each CompositorRenderPass to |
| // say if the render pass has damage. Ideally cc would just plumb the correct |
| // damage_rect and no bool. `has_damage` also takes into account if there is |
| // added damage from embedded content or filters that the client submitting |
| // the CompositorFrame didn't know about. |
| bool has_damage = false; |
| |
| // Indicates that the render pass is embedded from the root surface root |
| // render pass and will contribute pixels to framebuffer. Render passes this |
| // is false for may still be drawn but they won't contribute pixels to |
| // framebuffer. |
| bool will_draw = false; |
| |
| // The damage added from its descandant surfaces during aggregation. This is |
| // not part of the original render_pass->damage_rect from CC. |
| gfx::Rect added_damage; |
| |
| // |true| to if this pass should embedded and not merged. This is to support |
| // |kDelegatedCompositingLimitToUi| on Windows to keep the web contents |
| // surface in a swap chain instead of delegating its quads. |
| // TODO(crbug.com/324460866): Used for partially delegated compositing. |
| bool prevent_merge = false; |
| }; |
| |
| // Render pass data that must be recomputed each aggregation and needs to be |
| // persisted to next aggregation. |
| struct PersistentPassData { |
| PersistentPassData(); |
| PersistentPassData(PersistentPassData&& other); |
| PersistentPassData& operator=(PersistentPassData& other); |
| PersistentPassData& operator=(const PersistentPassData& other); |
| PersistentPassData& operator=(PersistentPassData&& other); |
| ~PersistentPassData(); |
| |
| enum MergeState { kInitState, kNotMerged, kAlwaysMerged, kSomeTimesMerged }; |
| |
| // The intersection of all render pass output rects, RenderPassDrawQuad rect, |
| // SurfaceDrawQuad rect, and clip rects from its ancestor render passes and |
| // surface. This is the max size this render pass can be rendered into the |
| // root surface. |parent_clip_rect| is in the dest root target space. |
| gfx::Rect parent_clip_rect; |
| |
| // Whether the render passes is merged with its parent render pass. The render |
| // mighe be embedded multiple times and has different status each time. |
| MergeState merge_state = kInitState; |
| }; |
| |
| // Data associated with a CompositorRenderPass in a resolved frame. Has fixed |
| // portion that does not change and an aggregation portion that does change. |
| class VIZ_SERVICE_EXPORT ResolvedPassData { |
| public: |
| explicit ResolvedPassData(FixedPassData fixed_data); |
| ~ResolvedPassData(); |
| ResolvedPassData(ResolvedPassData&& other); |
| ResolvedPassData& operator=(ResolvedPassData&& other); |
| |
| const CompositorRenderPass& render_pass() const; |
| AggregatedRenderPassId remapped_id() const { return fixed_.remapped_id; } |
| CompositorRenderPassId render_pass_id() const { |
| return fixed_.render_pass_id; |
| } |
| bool is_root() const { return fixed_.is_root; } |
| const std::vector<ResolvedQuadData>& draw_quads() const { |
| return fixed_.draw_quads; |
| } |
| |
| // Returns true if the render pass is not embedded by another render pass and |
| // is not the root render pass. |
| bool IsUnembedded() const { |
| return !fixed_.is_root && fixed_.embed_count == 0; |
| } |
| |
| AggregationPassData& aggregation() { return aggregation_; } |
| const AggregationPassData& aggregation() const { return aggregation_; } |
| |
| PersistentPassData& current_persistent_data() { |
| return current_persistent_data_; |
| } |
| |
| PersistentPassData& previous_persistent_data() { |
| return previous_persistent_data_; |
| } |
| |
| const PersistentPassData& previous_persistent_data() const { |
| return previous_persistent_data_; |
| } |
| |
| void CopyAndResetPersistentPassData(); |
| |
| // Set `fixed_.render_pass` to `pass`. Should be called at the beginning of an |
| // aggregation. |
| void SetCompositorRenderPass(CompositorRenderPass* pass); |
| |
| // Set `fixed_.render_pass` back to null, to avoid the dangling pointer |
| // after aggregation. Should be called at the end of an aggregation. |
| void ResetCompositorRenderPass(); |
| |
| private: |
| friend class ResolvedFrameData; |
| |
| // Data that is constant for the life of the resolved pass. |
| FixedPassData fixed_; |
| |
| // Data that will change each aggregation. |
| AggregationPassData aggregation_; |
| |
| PersistentPassData current_persistent_data_; |
| PersistentPassData previous_persistent_data_; |
| }; |
| |
| enum FrameDamageType { |
| // The CompositorFrame should be considered fully damaged. This could be the |
| // first CompositorFrame from the client, an intermediate CompositorFrame was |
| // skipped so the damage is unknown or there is synthetic damage. |
| kFull, |
| // The damage contained in the CompositorFrame should be used. |
| kFrame, |
| // The CompositorFrame is the same as last aggregation and has no damage. |
| kNone |
| }; |
| |
| // Holds computed information for a particular Surface+CompositorFrame. The |
| // CompositorFrame computed information will be updated whenever the active |
| // frame for the surface has changed. On destruction any resources registered |
| // with DisplayResourceProvider will be released. |
| // |
| // The first time a resolved frame is needed during aggregation |
| // UpdateForAggregation() then UpdateOffsetTags() must be called. That will |
| // populate all of the internal data. During aggregation the fixed data is |
| // viewed and aggregation data can be modified. After aggregation is over |
| // ResetAfterAggregation() will be called which resets aggregation data. |
| class VIZ_SERVICE_EXPORT ResolvedFrameData { |
| public: |
| using OffsetTagLookupFn = |
| base::FunctionRef<gfx::Vector2dF(const OffsetTagDefinition&)>; |
| |
| ResolvedFrameData(DisplayResourceProvider* resource_provider, |
| Surface* surface, |
| uint32_t prev_frame_index, |
| AggregatedRenderPassId prev_root_pass_id); |
| ~ResolvedFrameData(); |
| ResolvedFrameData(ResolvedFrameData&& other) = delete; |
| ResolvedFrameData& operator=(ResolvedFrameData&& other) = delete; |
| |
| const SurfaceId& surface_id() const { return surface_id_; } |
| Surface* surface() const { return surface_; } |
| bool is_valid() const { return valid_; } |
| uint32_t previous_frame_index() const { return previous_frame_index_; } |
| |
| gfx::Size size_in_pixels() const; |
| float device_scale_factor() const; |
| |
| // Returns namespace ID for the client that submitted this frame. This is used |
| // to deduplicate layer IDs from different clients. |
| std::pair<uint32_t, uint32_t> GetClientNamespaceId() const; |
| |
| void SetFullDamageForNextAggregation(); |
| |
| // Force release all resources registered with display resource provider. Note |
| // there must be a new CompositorFrame available that doesn't use any existing |
| // resources since resources (might) be missing on next draw. |
| void ForceReleaseResource(); |
| |
| // This must be called once before using ResolvedFrameData during aggregation. |
| // If there is a new active CompositorFrame data will be fully updated, see |
| // UpdatedActiveFrame() for details, otherwise previous data will be reused. |
| void UpdateForAggregation( |
| AggregatedRenderPassId::Generator& render_pass_id_generator); |
| |
| // This should be called each aggregation after UpdateForAggregation() to |
| // update resolved frame for OffsetTags. If the active CompositorFrame defines |
| // any tags, the tag values will be found and the resolved frame will be |
| // modified. |
| void UpdateOffsetTags(OffsetTagLookupFn lookup_value); |
| |
| // Sets frame index and marks as invalid. This also clears any existing |
| // resolved pass data. |
| void SetInvalid(); |
| |
| bool WasUsedInAggregation() const; |
| |
| // Resets aggregation data and WasUsedInAggregation() will now return false. |
| void ResetAfterAggregation(); |
| |
| // All functions after this point are accessors for the resolved frame and |
| // should only be called if is_valid() returns true. |
| |
| const CompositorFrameMetadata& GetMetadata() const; |
| |
| // Returns true if the root render pass is embedded from the the root surface |
| // root render pass. |
| bool WillDraw() const; |
| |
| // RenderPassData accessors. |
| ResolvedPassData& GetRenderPassDataById( |
| CompositorRenderPassId render_pass_id); |
| const ResolvedPassData& GetRenderPassDataById( |
| CompositorRenderPassId render_pass_id) const; |
| |
| ResolvedPassData& GetRootRenderPassData(); |
| const ResolvedPassData& GetRootRenderPassData() const; |
| |
| std::vector<ResolvedPassData>& GetResolvedPasses() { |
| return resolved_passes_; |
| } |
| const std::vector<ResolvedPassData>& GetResolvedPasses() const { |
| return resolved_passes_; |
| } |
| |
| // See `FrameDamageType` definition for what each status means. |
| FrameDamageType GetFrameDamageType() const; |
| |
| // Returns surface damage rect. This is based on changes from the |
| // CompositorFrame aggregated last frame. This limited to the root render |
| // passes damage_rect and does not include individual quads that add damage. |
| gfx::Rect GetSurfaceDamage() const; |
| |
| // Returns the root render pass output_rect. |
| const gfx::Rect& GetOutputRect() const; |
| |
| private: |
| friend class ResolvedFrameDataTestHelper; |
| |
| // Data for a specific `OffsetTag`. |
| struct OffsetTagData { |
| // The offset value that is used. |
| gfx::Vector2dF last_offset; |
| gfx::Vector2dF current_offset; |
| // The containing rect is the union of all tagged quad visible rects in |
| // root render pass coordinate space before applying any offsets. |
| gfx::Rect last_containing_rect; |
| gfx::Rect current_containing_rect; |
| bool defined_in_frame = false; |
| }; |
| |
| // Updates ResolvedPassData for a new active frame. It also updates surface |
| // client and display resource provider with resources used in the new active |
| // frame. |
| // |
| // This performs the following validation on the active CompositorFrame. |
| // 1. Checks each ResourceId was registered with DisplayResourceProvider and |
| // is in |child_to_parent_map|. |
| // 2. Checks that CompositorRenderPasses have unique ids. |
| // 3. Checks that CompositorRenderPassDrawQuads only embed render passes that |
| // are drawn before. This has the side effect of disallowing any cycles. |
| // |
| // If validation fails then ResolvedPassData will be cleared and is_valid() |
| // will return false. |
| void UpdateActiveFrame( |
| AggregatedRenderPassId::Generator& render_pass_id_generator); |
| |
| // Set `CompositorRenderPass` for all `resolved_passes_`. Each |
| // `ResolvedPassData` must have been aggregated before. |
| void ReuseActiveFrame(); |
| |
| void RegisterWithResourceProvider(); |
| void MovePersistentPassDataFromPreviousFrame( |
| const std::vector<ResolvedPassData>& previoius_resolved_passes); |
| |
| void ComputeOffsetTagContainingRects(); |
| void RebuildRenderPassesForOffsetTags(); |
| void RecomputeOffsetTagDamage(); |
| |
| const raw_ptr<DisplayResourceProvider> resource_provider_; |
| const SurfaceId surface_id_; |
| const raw_ptr<Surface> surface_; |
| |
| // Child resource ID assigned by `resource_provider_`. |
| int child_resource_id_ = 0; |
| |
| // Data associated with CompositorFrame with |frame_index_|. |
| bool valid_ = false; |
| uint32_t frame_index_ = kInvalidFrameIndex; |
| uint32_t previous_frame_index_ = kInvalidFrameIndex; |
| |
| base::flat_map<OffsetTag, OffsetTagData> offset_tag_data_; |
| // Additional damage that is due to OffsetTag changes between aggregations |
| // that is unioned into the surface damage. |
| gfx::Rect offset_tag_added_damage_; |
| bool has_non_zero_offset_tag_value_ = false; |
| |
| // Holds a modified copy of render passes from current active CompositorFrame. |
| std::vector<std::unique_ptr<CompositorRenderPass>> offset_tag_render_passes_; |
| |
| std::vector<ResolvedPassData> resolved_passes_; |
| base::flat_map<CompositorRenderPassId, |
| raw_ptr<ResolvedPassData, CtnExperimental>> |
| render_pass_id_map_; |
| base::flat_map<CompositorRenderPassId, AggregatedRenderPassId> |
| aggregated_id_map_; |
| |
| const AggregatedRenderPassId prev_root_pass_id_; |
| |
| // Track if the this resolved frame was used this aggregation. |
| bool used_in_aggregation_ = false; |
| }; |
| |
| } // namespace viz |
| |
| #endif // COMPONENTS_VIZ_SERVICE_DISPLAY_RESOLVED_FRAME_DATA_H_ |