// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_DC_LAYER_OVERLAY_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_DC_LAYER_OVERLAY_H_
#include <vector>
#include "base/check_is_test.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/power_monitor/power_monitor.h"
#include "base/threading/thread_checker.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/video_types.h"
#include "ui/gl/direct_composition_support.h"
namespace viz {
class DisplayResourceProvider;
class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor final
: public gl::DirectCompositionOverlayCapsObserver,
public base::PowerStateObserver {
public:
using FilterOperationsMap =
base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>;
// When |skip_initialization_for_testing| is true, object will be isolated
// for unit tests.
explicit DCLayerOverlayProcessor(
int allowed_yuv_overlay_count,
bool skip_initialization_for_testing = false);
DCLayerOverlayProcessor(const DCLayerOverlayProcessor&) = delete;
DCLayerOverlayProcessor& operator=(const DCLayerOverlayProcessor&) = delete;
~DCLayerOverlayProcessor() override;
// Encapsulates all of the information about a render pass's overlays that
// are returned back to OverlayProcessorWin. This is passed to Process() as an
// in/out parameter.
struct VIZ_SERVICE_EXPORT RenderPassOverlayData {
RenderPassOverlayData();
~RenderPassOverlayData();
RenderPassOverlayData(RenderPassOverlayData&&);
RenderPassOverlayData& operator=(RenderPassOverlayData&&);
// Damage rect of the render pass. Set by OverlayProcessorWin and may be
// optimized in UpdateDamageRect() if overlays are promoted.
gfx::Rect damage_rect;
// List of overlays that are actually promoted. Only used for output back to
// OverlayProcessorWin. Contains all the information necessary to draw the
// overlay quads in SkiaRenderer.
OverlayCandidateList promoted_overlays;
};
using RenderPassOverlayDataMap =
base::flat_map<raw_ptr<AggregatedRenderPass>, RenderPassOverlayData>;
// Virtual for testing. All render passes that should be considered for
// overlays in this frame should be in |render_pass_overlay_data_map|. After
// this function executes, |render_pass_overlay_data_map[render_pass]| will
// contain the all of the overlays promoted for |render_pass|. The z-order
// of the overlays are assigned relative to other overlays within the render
// pass, with positive z-orders being overlays and negative z-orders being
// underlays. The caller must aggregate overlays from all render passes into
// a global overlay list, taking into account the render pass's z-order.
virtual void Process(
const DisplayResourceProvider* resource_provider,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
const SurfaceDamageRectList& surface_damage_rect_list_in_root_space,
bool is_page_fullscreen_mode,
RenderPassOverlayDataMap& render_pass_overlay_data_map);
// DirectCompositionOverlayCapsObserver implementation.
void OnOverlayCapsChanged() override;
// base::PowerStateObserver implementation.
void OnPowerStateChange(bool on_battery_power) override;
void UpdateHasHwOverlaySupport();
void UpdateSystemHDRStatus();
void UpdateP010VideoProcessorSupport();
void UpdateAutoHDRVideoProcessorSupport();
void set_frames_since_last_qualified_multi_overlays_for_testing(int value) {
frames_since_last_qualified_multi_overlays_ = value;
}
void set_system_hdr_enabled_on_any_display_for_testing(bool value) {
system_hdr_enabled_on_any_display_ = value;
}
void set_system_hdr_disabled_on_any_display_for_testing(bool value) {
system_hdr_disabled_on_any_display_ = value;
}
void set_has_p010_video_processor_support_for_testing(bool value) {
has_p010_video_processor_support_ = value;
}
void set_has_auto_hdr_video_processor_support_for_testing(bool value) {
has_auto_hdr_video_processor_support_ = value;
}
void set_is_on_battery_power_for_testing(bool value) {
is_on_battery_power_ = value;
}
bool force_overlay_for_auto_hdr() {
return system_hdr_enabled_on_any_display_ &&
has_auto_hdr_video_processor_support_ && !is_on_battery_power_;
}
size_t get_previous_frame_render_pass_count() const {
CHECK_IS_TEST();
return previous_frame_render_pass_states_.size();
}
std::vector<AggregatedRenderPassId> get_previous_frame_render_pass_ids()
const {
std::vector<AggregatedRenderPassId> ids;
for (const auto& [id, _] : previous_frame_render_pass_states_) {
ids.push_back(id);
}
return ids;
}
// This struct only contains minimal information about the overlays, enough to
// perform damage optimizations across frames.
struct OverlayRect {
gfx::Rect rect;
bool is_overlay = true; // If false, it's an underlay.
friend bool operator==(const OverlayRect&, const OverlayRect&) = default;
};
// Promote a single quad in isolation, like how |Process| would internally.
// This ignores per-frame limitations such as max number of YUV quads, etc.
// This also adds other properties needed for delegated compositing.
std::optional<OverlayCandidate> FromTextureOrYuvQuad(
const DisplayResourceProvider* resource_provider,
const AggregatedRenderPass* render_pass,
const QuadList::ConstIterator& it,
bool is_page_fullscreen_mode) const;
private:
// Information about a render pass's overlays from the previous frame. The
// previous frame's overlays are used for optimizations, which are done
// independently for each render pass. These optimizations try to remove
// render pass packing damage if the overlays are not changed between frames,
// which potentially allows us to skip drawing the render pass. We also add
// damage from overlays in the previous frame in the scenarios where we skip
// overlays in the current frame or if the overlays have changed. This damage
// needs to be re-added because the content under the overlays from the
// previous frame are likely out of date if they were optimized out.
struct RenderPassPreviousFrameState {
RenderPassPreviousFrameState();
~RenderPassPreviousFrameState();
RenderPassPreviousFrameState(RenderPassPreviousFrameState&&);
RenderPassPreviousFrameState& operator=(
RenderPassPreviousFrameState&& other);
// Whether the render pass had any promoted underlay quads that were opaque
// in the previous frame.
bool underlay_is_opaque = true;
// The output rect of the render pass in the previous frame.
gfx::Rect display_rect;
// Rects of all overlay and underlay quads that were promoted in the
// previous frame.
std::vector<OverlayRect> overlay_rects;
};
// Information about a render pass's overlays in the current frame being
// processed. This struct primarily serves to encapsulate all parameters
// relating to a render pass into one object that can be passed between
// multiple functions. These objects do not persist after this current frame
// is processed. While RenderPassOverlayData stores information that are
// exposed and returned to OverlayProcessorWin, this struct contains data used
// only internally to this class.
struct RenderPassCurrentFrameState {
RenderPassCurrentFrameState();
~RenderPassCurrentFrameState();
RenderPassCurrentFrameState(RenderPassCurrentFrameState&&);
RenderPassCurrentFrameState& operator=(RenderPassCurrentFrameState&& other);
// The surface damage rect list for the frame, in *render pass space*.
SurfaceDamageRectList surface_damage_rect_list;
// Overlay quad candidates in the render pass's quad list. These are
// overlays that have been identified as potential candidates for promotion
// and are collected in the initial stage of processing. Some or all of
// these candidates may or may not be actually promoted. We're storing
// iterators instead of the actual quad because some functions such as
// IsPossiblefullScreenLetterboxing and ProcessForUnderlay require knowing
// the position of the quad in the quad list.
std::vector<QuadList::Iterator> candidates;
// Rects of overlays that have been processed and successfully promoted and
// added to |RenderPassOverlayData::promoted_overlays|.
std::vector<OverlayRect> overlay_rects;
// Overlay damages that can be removed from the render pass's damage rect
// at the end of processing overlays. This vector stores indices of damages
// in |surface_damage_rect_list| that can be removed.
std::vector<size_t> damages_to_be_removed;
};
using RenderPassCurrentFrameStateMap =
base::flat_map<raw_ptr<AggregatedRenderPass>,
RenderPassCurrentFrameState>;
// Information about overlays in the current frame being processed. Unlike
// fields in RenderPassCurrentFrameState, these fields are not specific to any
// render pass. They are global to the entire frame. Similarly, this struct
// exists primarily to encapsulate variables into one object to pass between
// functions.
struct GlobalOverlayState {
// Actual number of yuv quads that are successfully processed and added as
// an overlay. Used to determine whether overlay should be skipped.
int processed_yuv_overlay_count = 0;
// Total number of yuv quads.
int yuv_quads = 0;
// Number of yuv quads that were considered for overlay promotion and have a
// non-empty surface damage.
int damaged_yuv_quads = 0;
// Tracks whether we have anything other than clear video overlays e.g. low
// latency canvas or protected video which are allowed for multiple
// overlays.
bool has_non_clear_video_overlays = false;
// Used for recording overlay histograms.
bool has_occluding_damage_rect = false;
// Whether to reject all overlays for this frame. This can be true if we
// have more than one overlay quad and not all of them are promoted to
// overlays.
bool reject_overlays = false;
};
// Collects the overlay candidates for a render pass. Coordinate systems for
// all parameters should be in render pass space.
//
// If video capture is enabled, overlays are not processed. In this case, the
// render pass's previous frame data is erased since there will be no overlays
// in the current frame.
//
// This function adds overlay candidates for |render_pass| into
// |render_pass_state| and accumulates information about |render_pass|
// into |global_overlay_state|. If overlays should be skipped for this
// render pass, the damage rect in |overlay_data| is unioned with the previous
// frame's overlay damages, and the previous frame state is cleared.
void CollectCandidates(
const DisplayResourceProvider* resource_provider,
AggregatedRenderPass* render_pass,
const FilterOperationsMap& render_pass_backdrop_filters,
RenderPassOverlayData& overlay_data,
RenderPassCurrentFrameState& render_pass_state,
GlobalOverlayState& global_overlay_state);
// Promotes overlay candidates for a render pass. Coordinate systems for all
// parameters should be in in render pass space.
//
// The render pass's corresponding RenderPassPreviousFrameState object in
// |previous_frame_overlay_candidate_rects_| is updated to contain this
// frame's data.
//
// This function adds overlays that have been promoted into |overlay_data|
// and accumulates their rects into the damage rect. It also updates all of
// |current_frame_state|'s fields and |processed_yuv_overlay_count| to reflect
// the actual number of overlays promoted.
void PromoteCandidates(
const DisplayResourceProvider* resource_provider,
AggregatedRenderPass* render_pass,
const FilterOperationsMap& render_pass_filters,
const RenderPassPreviousFrameState& previous_frame_state,
bool is_page_fullscreen_mode,
RenderPassOverlayData& overlay_data,
RenderPassCurrentFrameState& current_frame_state,
GlobalOverlayState& global_overlay_state);
// Detects overlay processing skip inside |render_pass|.
bool ShouldSkipOverlay(AggregatedRenderPass* render_pass) const;
// Creates an OverlayCandidate for a quad candidate and updates the states
// for the render pass.
void UpdateDCLayerOverlays(
const DisplayResourceProvider* resource_provider,
AggregatedRenderPass* render_pass,
const QuadList::Iterator& it,
const gfx::Rect& quad_rectangle_in_target_space,
const RenderPassPreviousFrameState& previous_frame_state,
bool is_overlay,
bool is_page_fullscreen_mode,
RenderPassOverlayData& overlay_data,
RenderPassCurrentFrameState& current_frame_state,
GlobalOverlayState& global_overlay_state);
void ProcessForOverlay(
AggregatedRenderPass* render_pass,
const QuadList::Iterator& it,
const RenderPassPreviousFrameState& previous_frame_state,
RenderPassCurrentFrameState& current_frame_state) const;
void ProcessForUnderlay(
AggregatedRenderPass* render_pass,
const QuadList::Iterator& it,
const gfx::Rect& quad_rectangle_in_target_space,
const RenderPassPreviousFrameState& previous_frame_state,
const GlobalOverlayState& global_overlay_state,
RenderPassOverlayData& overlay_data,
RenderPassCurrentFrameState& current_frame_state,
OverlayCandidate& dc_layer);
void UpdateDamageRect(
AggregatedRenderPass* render_pass,
const RenderPassPreviousFrameState& previous_frame_state,
RenderPassOverlayData& overlay_data,
RenderPassCurrentFrameState& current_frame_state) const;
void RemoveOverlayDamageRect(
const QuadList::Iterator& it,
RenderPassCurrentFrameState& render_pass_state) const;
// Remove all video overlay candidates if any overlays in any render passes
// have moved in the last several frames.
//
// We do this because it could cause visible stuttering of playback on certain
// older hardware. The stuttering does not occur if other overlay quads move
// while a non-moving video is playing.
//
// This only tracks clear video quads because hardware-protected videos cannot
// be accessed by the viz compositor, so they must be promoted to overlay,
// even if they could cause stutter. Software-protected video aren't required
// to be in overlay, but we also exclude them from de-promotion to keep the
// protection benefits of being in an overlay.
void RemoveClearVideoQuadCandidatesIfMoving(
const DisplayResourceProvider* resource_provider,
RenderPassOverlayDataMap& render_pass_overlay_data_map,
RenderPassCurrentFrameStateMap& render_pass_current_state_map);
bool has_overlay_support_;
bool has_p010_video_processor_support_ = false;
bool has_auto_hdr_video_processor_support_ = false;
// At least one monitor that has system HDR enabled.
bool system_hdr_enabled_on_any_display_ = false;
// At least one monitor that has system HDR disabled or doesn't support HDR.
bool system_hdr_disabled_on_any_display_ = true;
const int allowed_yuv_overlay_count_;
uint64_t frames_since_last_qualified_multi_overlays_ = 0;
bool allow_promotion_hinting_ = false;
bool is_on_battery_power_ = false;
// Information about overlays from the previous frame.
base::flat_map<AggregatedRenderPassId, RenderPassPreviousFrameState>
previous_frame_render_pass_states_;
// Used in `RemoveClearVideoQuadCandidatesIfMoving`
// List of clear video content candidate bounds. These rects are in root space
// and contains the candidate rects for all render passes.
// TODO(crbug.com/40272272): Compute these values using
// |previous_frame_render_pass_states_| and remove this field.
std::vector<gfx::Rect> previous_frame_overlay_candidate_rects_;
int frames_since_last_overlay_candidate_rects_change_ = 0;
bool no_undamaged_overlay_promotion_;
THREAD_CHECKER(thread_checker_);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DC_LAYER_OVERLAY_H_