blob: ce590b9526220b28ee0dde118a406f409522a22d [file] [log] [blame]
// Copyright 2015 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_strategy_sandwich.h"
#include "cc/base/math_util.h"
#include "cc/base/region.h"
#include "cc/output/overlay_candidate_validator.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
namespace cc {
namespace {
void ClipDisplayAndUVRects(gfx::Rect* display_rect,
gfx::RectF* uv_rect,
const gfx::Rect& clip_rect) {
gfx::Rect display_cropped_rect =
gfx::IntersectRects(*display_rect, clip_rect);
gfx::RectF uv_cropped_rect = gfx::RectF(display_cropped_rect);
uv_cropped_rect -= gfx::Vector2dF(display_rect->x(), display_rect->y());
uv_cropped_rect.Scale(uv_rect->width() / display_rect->width(),
uv_rect->height() / display_rect->height());
uv_cropped_rect += gfx::Vector2dF(uv_rect->x(), uv_rect->y());
*display_rect = display_cropped_rect;
*uv_rect = uv_cropped_rect;
}
} // namespace
OverlayStrategySandwich::OverlayStrategySandwich(
OverlayCandidateValidator* capability_checker)
: capability_checker_(capability_checker) {
DCHECK(capability_checker);
}
OverlayStrategySandwich::~OverlayStrategySandwich() {}
bool OverlayStrategySandwich::Attempt(ResourceProvider* resource_provider,
RenderPassList* render_passes,
OverlayCandidateList* candidate_list) {
QuadList& quad_list = render_passes->back()->quad_list;
for (auto it = quad_list.begin(); it != quad_list.end();) {
OverlayCandidate candidate;
if (OverlayCandidate::FromDrawQuad(resource_provider, *it, &candidate)) {
it = TryOverlay(render_passes->back().get(), candidate_list, candidate,
it);
} else {
++it;
}
}
return candidate_list->size() > 1;
}
QuadList::Iterator OverlayStrategySandwich::TryOverlay(
RenderPass* render_pass,
OverlayCandidateList* candidate_list,
const OverlayCandidate& candidate,
QuadList::Iterator candidate_iter_in_quad_list) {
QuadList& quad_list = render_pass->quad_list;
gfx::Rect pixel_bounds = render_pass->output_rect;
const DrawQuad* candidate_quad = *candidate_iter_in_quad_list;
const gfx::Transform& candidate_transform =
candidate_quad->shared_quad_state->quad_to_target_transform;
gfx::Transform candidate_inverse_transform;
if (!candidate_transform.GetInverse(&candidate_inverse_transform))
return ++candidate_iter_in_quad_list;
// Compute the candidate's rect in display space (pixels on the screen).
gfx::Rect candidate_pixel_rect = candidate.quad_rect_in_target_space;
gfx::RectF candidate_uv_rect = candidate.uv_rect;
if (candidate.is_clipped &&
!candidate.clip_rect.Contains(candidate_pixel_rect)) {
ClipDisplayAndUVRects(&candidate_pixel_rect, &candidate_uv_rect,
candidate.clip_rect);
}
// Don't allow overlapping overlays for now.
for (const OverlayCandidate& other_candidate : *candidate_list) {
if (other_candidate.display_rect.Intersects(candidate.display_rect) &&
other_candidate.plane_z_order == 1) {
return ++candidate_iter_in_quad_list;
}
}
// Iterate through the quads in front of |candidate|, and compute the region
// of |candidate| that is covered.
Region pixel_covered_region;
for (auto overlap_iter = quad_list.cbegin();
overlap_iter != candidate_iter_in_quad_list; ++overlap_iter) {
if (OverlayCandidate::IsInvisibleQuad(*overlap_iter))
continue;
// Compute the quad's bounds in display space.
gfx::Rect pixel_covered_rect = MathUtil::MapEnclosingClippedRect(
overlap_iter->shared_quad_state->quad_to_target_transform,
overlap_iter->rect);
// Include the intersection of that quad with the candidate's quad in the
// covered region.
pixel_covered_rect.Intersect(candidate_pixel_rect);
pixel_covered_region.Union(pixel_covered_rect);
}
// Add the candidate's overlay.
DCHECK(candidate.resource_id);
OverlayCandidateList new_candidate_list = *candidate_list;
new_candidate_list.push_back(candidate);
OverlayCandidate& new_candidate = new_candidate_list.back();
new_candidate.plane_z_order = 1;
new_candidate.display_rect = gfx::RectF(candidate_pixel_rect);
new_candidate.quad_rect_in_target_space = candidate_pixel_rect;
new_candidate.uv_rect = candidate_uv_rect;
// Add an overlay of the primary surface for any part of the candidate's
// quad that was covered.
std::vector<gfx::Rect> pixel_covered_rects;
for (Region::Iterator it(pixel_covered_region); it.has_rect(); it.next())
pixel_covered_rects.push_back(it.rect());
for (const gfx::Rect& pixel_covered_rect : pixel_covered_rects) {
OverlayCandidate main_image_on_top;
main_image_on_top.display_rect = gfx::RectF(pixel_covered_rect);
main_image_on_top.uv_rect = gfx::RectF(pixel_covered_rect);
main_image_on_top.uv_rect.Scale(1.f / pixel_bounds.width(),
1.f / pixel_bounds.height());
main_image_on_top.plane_z_order = 2;
main_image_on_top.transform = gfx::OVERLAY_TRANSFORM_NONE;
main_image_on_top.use_output_surface_for_resource = true;
new_candidate_list.push_back(main_image_on_top);
}
// Check for support.
capability_checker_->CheckOverlaySupport(&new_candidate_list);
for (const OverlayCandidate& candidate : new_candidate_list) {
if (!candidate.overlay_handled)
return ++candidate_iter_in_quad_list;
}
// Remove the quad for the overlay quad. Replace it with a transparent quad
// if we're putting a new overlay on top.
if (pixel_covered_rects.empty()) {
candidate_iter_in_quad_list =
quad_list.EraseAndInvalidateAllPointers(candidate_iter_in_quad_list);
} else {
// Cache the information from the candidate quad that we'll need to
// construct the solid color quads.
const SharedQuadState* candidate_shared_quad_state =
candidate_quad->shared_quad_state;
const gfx::Rect candidate_rect = candidate_quad->rect;
// Reserve space in the quad list for the transparent quads.
quad_list.ReplaceExistingElement<SolidColorDrawQuad>(
candidate_iter_in_quad_list);
candidate_iter_in_quad_list =
quad_list.InsertBeforeAndInvalidateAllPointers<SolidColorDrawQuad>(
candidate_iter_in_quad_list, pixel_covered_rects.size() - 1);
// Cover the region with transparent quads.
for (const gfx::Rect& pixel_covered_rect : pixel_covered_rects) {
gfx::Rect quad_space_covered_rect = MathUtil::MapEnclosingClippedRect(
candidate_inverse_transform, pixel_covered_rect);
quad_space_covered_rect.Intersect(candidate_rect);
SolidColorDrawQuad* transparent_quad =
static_cast<SolidColorDrawQuad*>(*candidate_iter_in_quad_list);
transparent_quad->SetAll(candidate_shared_quad_state,
quad_space_covered_rect, quad_space_covered_rect,
quad_space_covered_rect, false,
SK_ColorTRANSPARENT, true);
++candidate_iter_in_quad_list;
}
}
candidate_list->swap(new_candidate_list);
return candidate_iter_in_quad_list;
}
} // namespace cc