blob: 74e68d22cd0373279b7bc26add8cad7d17ff8e36 [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.
#include "cc/output/overlay_processor.h"
#include "cc/output/output_surface.h"
#include "cc/output/overlay_strategy_single_on_top.h"
#include "cc/output/overlay_strategy_underlay.h"
#include "cc/quads/draw_quad.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
namespace cc {
OverlayProcessor::OverlayProcessor(OutputSurface* surface) : surface_(surface) {
}
void OverlayProcessor::Initialize() {
DCHECK(surface_);
OverlayCandidateValidator* validator =
surface_->GetOverlayCandidateValidator();
if (validator)
validator->GetStrategies(&strategies_);
}
OverlayProcessor::~OverlayProcessor() {}
gfx::Rect OverlayProcessor::GetAndResetOverlayDamage() {
gfx::Rect result = overlay_damage_rect_;
overlay_damage_rect_ = gfx::Rect();
return result;
}
bool OverlayProcessor::ProcessForCALayers(
ResourceProvider* resource_provider,
RenderPassList* render_passes,
OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect) {
RenderPass* root_render_pass = render_passes->back().get();
OverlayCandidateValidator* overlay_validator =
surface_->GetOverlayCandidateValidator();
if (!overlay_validator || !overlay_validator->AllowCALayerOverlays())
return false;
if (!ProcessForCALayerOverlays(
resource_provider, gfx::RectF(root_render_pass->output_rect),
root_render_pass->quad_list, ca_layer_overlays))
return false;
// CALayer overlays are all-or-nothing. If all quads were replaced with
// layers then clear the list and remove the backbuffer from the overcandidate
// list.
overlay_candidates->clear();
render_passes->back()->quad_list.clear();
overlay_damage_rect_ = root_render_pass->output_rect;
*damage_rect = gfx::Rect();
return true;
}
void OverlayProcessor::ProcessForOverlays(ResourceProvider* resource_provider,
RenderPassList* render_passes,
OverlayCandidateList* candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect) {
// First attempt to process for CALayers.
if (ProcessForCALayers(resource_provider, render_passes, candidates,
ca_layer_overlays, damage_rect)) {
return;
}
// Only if that fails, attempt hardware overlay strategies.
for (const auto& strategy : strategies_) {
if (!strategy->Attempt(resource_provider, render_passes, candidates))
continue;
UpdateDamageRect(candidates, damage_rect);
return;
}
}
void OverlayProcessor::SkipProcessForOverlays() {
// If overlay processing was skipped for a frame there's no way to be sure
// of the state of the previous frame, so reset.
previous_frame_underlay_rect_ = gfx::Rect();
}
// Subtract on-top overlays from the damage rect, unless the overlays use
// the backbuffer as their content (in which case, add their combined rect
// back to the damage at the end).
// Also subtract unoccluded underlays from the damage rect if we know that the
// same underlay was scheduled on the previous frame. If the renderer decides
// not to swap the framebuffer there will still be a transparent hole in the
// previous frame. This only handles the common case of a single underlay quad
// for fullscreen video.
void OverlayProcessor::UpdateDamageRect(OverlayCandidateList* candidates,
gfx::Rect* damage_rect) {
gfx::Rect output_surface_overlay_damage_rect;
gfx::Rect this_frame_underlay_rect;
for (const OverlayCandidate& overlay : *candidates) {
if (overlay.plane_z_order > 0) {
const gfx::Rect overlay_display_rect =
ToEnclosedRect(overlay.display_rect);
overlay_damage_rect_.Union(overlay_display_rect);
damage_rect->Subtract(overlay_display_rect);
if (overlay.use_output_surface_for_resource)
output_surface_overlay_damage_rect.Union(overlay_display_rect);
} else if (overlay.plane_z_order < 0 && overlay.is_unoccluded &&
this_frame_underlay_rect.IsEmpty()) {
this_frame_underlay_rect = ToEnclosedRect(overlay.display_rect);
}
}
if (this_frame_underlay_rect == previous_frame_underlay_rect_)
damage_rect->Subtract(this_frame_underlay_rect);
previous_frame_underlay_rect_ = this_frame_underlay_rect;
damage_rect->Union(output_surface_overlay_damage_rect);
}
} // namespace cc