| Index: cc/output/dc_layer_overlay.cc
|
| diff --git a/cc/output/dc_layer_overlay.cc b/cc/output/dc_layer_overlay.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3523c4519ac489361cf0f0a03a1df4dbd11b45c1
|
| --- /dev/null
|
| +++ b/cc/output/dc_layer_overlay.cc
|
| @@ -0,0 +1,184 @@
|
| +// Copyright 2017 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/dc_layer_overlay.h"
|
| +
|
| +#include "cc/base/math_util.h"
|
| +#include "cc/quads/solid_color_draw_quad.h"
|
| +#include "cc/quads/yuv_video_draw_quad.h"
|
| +#include "cc/resources/resource_provider.h"
|
| +#include "gpu/GLES2/gl2extchromium.h"
|
| +#include "ui/gfx/geometry/rect_conversions.h"
|
| +
|
| +namespace cc {
|
| +
|
| +namespace {
|
| +
|
| +DCLayerOverlayProcessor::DCLayerResult FromYUVQuad(
|
| + ResourceProvider* resource_provider,
|
| + const YUVVideoDrawQuad* quad,
|
| + DCLayerOverlay* ca_layer_overlay) {
|
| + unsigned resource_id = quad->y_plane_resource_id();
|
| + if (!resource_provider->IsOverlayCandidate(resource_id))
|
| + return DCLayerOverlayProcessor::DC_LAYER_FAILED_TEXTURE_NOT_CANDIDATE;
|
| + ca_layer_overlay->contents_resource_id = resource_id;
|
| + ca_layer_overlay->contents_rect = quad->ya_tex_coord_rect;
|
| + ca_layer_overlay->filter = GL_LINEAR;
|
| + return DCLayerOverlayProcessor::DC_LAYER_SUCCESS;
|
| +}
|
| +
|
| +// Find a rectangle containing all the quads in a list that occlude the area
|
| +// in target_quad.
|
| +gfx::RectF GetOcclusionBounds(const gfx::RectF& target_quad,
|
| + QuadList::ConstIterator quad_list_begin,
|
| + QuadList::ConstIterator quad_list_end) {
|
| + gfx::RectF occlusion_bounding_box;
|
| + for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
|
| + ++overlap_iter) {
|
| + gfx::RectF overlap_rect = MathUtil::MapClippedRect(
|
| + overlap_iter->shared_quad_state->quad_to_target_transform,
|
| + gfx::RectF(overlap_iter->rect));
|
| + float opacity = overlap_iter->shared_quad_state->opacity;
|
| + if (opacity < std::numeric_limits<float>::epsilon())
|
| + continue;
|
| + const DrawQuad* quad = *overlap_iter;
|
| + if (quad->material == DrawQuad::SOLID_COLOR) {
|
| + SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
|
| + float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
|
| + if (quad->ShouldDrawWithBlending() &&
|
| + alpha < std::numeric_limits<float>::epsilon())
|
| + continue;
|
| + }
|
| + overlap_rect.Intersect(target_quad);
|
| + if (!overlap_rect.IsEmpty()) {
|
| + occlusion_bounding_box.Union(overlap_rect);
|
| + }
|
| + }
|
| + return occlusion_bounding_box;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +DCLayerOverlay::DCLayerOverlay() : filter(GL_LINEAR) {}
|
| +
|
| +DCLayerOverlay::DCLayerOverlay(const DCLayerOverlay& other) = default;
|
| +
|
| +DCLayerOverlay::~DCLayerOverlay() {}
|
| +
|
| +DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
|
| + ResourceProvider* resource_provider,
|
| + const gfx::RectF& display_rect,
|
| + QuadList::ConstIterator quad_list_begin,
|
| + QuadList::ConstIterator quad,
|
| + DCLayerOverlay* ca_layer_overlay) {
|
| + if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
|
| + return DC_LAYER_FAILED_QUAD_BLEND_MODE;
|
| +
|
| + DCLayerResult result = DC_LAYER_FAILED_UNKNOWN;
|
| + switch (quad->material) {
|
| + case DrawQuad::YUV_VIDEO_CONTENT:
|
| + result =
|
| + FromYUVQuad(resource_provider, YUVVideoDrawQuad::MaterialCast(*quad),
|
| + ca_layer_overlay);
|
| + break;
|
| + default:
|
| + return DC_LAYER_FAILED_UNKNOWN;
|
| + }
|
| + if (result != DC_LAYER_SUCCESS)
|
| + return result;
|
| +
|
| + scoped_refptr<DCLayerOverlaySharedState> overlay_shared_state(
|
| + new DCLayerOverlaySharedState);
|
| + overlay_shared_state->z_order = 1;
|
| +
|
| + overlay_shared_state->is_clipped = quad->shared_quad_state->is_clipped;
|
| + overlay_shared_state->clip_rect =
|
| + gfx::RectF(quad->shared_quad_state->clip_rect);
|
| +
|
| + overlay_shared_state->opacity = quad->shared_quad_state->opacity;
|
| + overlay_shared_state->transform =
|
| + quad->shared_quad_state->quad_to_target_transform.matrix();
|
| +
|
| + ca_layer_overlay->shared_state = overlay_shared_state;
|
| + ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
|
| +
|
| + return result;
|
| +}
|
| +
|
| +void DCLayerOverlayProcessor::Process(ResourceProvider* resource_provider,
|
| + const gfx::RectF& display_rect,
|
| + QuadList* quad_list,
|
| + gfx::Rect* overlay_damage_rect,
|
| + gfx::Rect* damage_rect,
|
| + DCLayerOverlayList* ca_layer_overlays) {
|
| + gfx::Rect this_frame_underlay_rect;
|
| + for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
|
| + DCLayerOverlay ca_layer;
|
| + DCLayerResult result = FromDrawQuad(resource_provider, display_rect,
|
| + quad_list->begin(), it, &ca_layer);
|
| + if (result != DC_LAYER_SUCCESS)
|
| + continue;
|
| + gfx::Rect quad_rectangle = MathUtil::MapEnclosingClippedRect(
|
| + it->shared_quad_state->quad_to_target_transform, it->rect);
|
| + gfx::RectF occlusion_bounding_box =
|
| + GetOcclusionBounds(gfx::RectF(quad_rectangle), quad_list->begin(), it);
|
| +
|
| + if (occlusion_bounding_box.IsEmpty()) {
|
| + // The quad is on top, so promote it to an overlay and remove all damage
|
| + // underneath it.
|
| + if (it->shared_quad_state->quad_to_target_transform
|
| + .Preserves2dAxisAlignment()) {
|
| + damage_rect->Subtract(quad_rectangle);
|
| + overlay_damage_rect->Union(quad_rectangle);
|
| + }
|
| + quad_list->EraseAndInvalidateAllPointers(it);
|
| + } else {
|
| + // The quad is occluded, so replace it with a black solid color quad and
|
| + // place the overlay itself under the quad.
|
| + if (it->shared_quad_state->quad_to_target_transform
|
| + .IsIdentityOrIntegerTranslation()) {
|
| + this_frame_underlay_rect = quad_rectangle;
|
| + }
|
| + ca_layer.shared_state->z_order = -1;
|
| + const SharedQuadState* shared_quad_state = it->shared_quad_state;
|
| + gfx::Rect rect = it->visible_rect;
|
| + SolidColorDrawQuad* replacement =
|
| + quad_list->ReplaceExistingElement<SolidColorDrawQuad>(it);
|
| + replacement->SetAll(shared_quad_state, rect, rect, rect, false,
|
| + SK_ColorTRANSPARENT, true);
|
| +
|
| + if (this_frame_underlay_rect == previous_frame_underlay_rect_) {
|
| + // If this underlay rect is the same as for last frame, subtract its
|
| + // area from the damage of the main surface, as the cleared area was
|
| + // already cleared last frame. Add back the damage from the occluded
|
| + // area for this and last frame, as that may have changed.
|
| + if (it->shared_quad_state->quad_to_target_transform
|
| + .Preserves2dAxisAlignment()) {
|
| + gfx::Rect occluding_damage_rect = *damage_rect;
|
| + occluding_damage_rect.Intersect(quad_rectangle);
|
| + damage_rect->Subtract(quad_rectangle);
|
| + gfx::Rect new_occlusion_bounding_box =
|
| + gfx::ToEnclosingRect(occlusion_bounding_box);
|
| + new_occlusion_bounding_box.Union(previous_occlusion_bounding_box_);
|
| + occluding_damage_rect.Intersect(new_occlusion_bounding_box);
|
| +
|
| + damage_rect->Union(occluding_damage_rect);
|
| + overlay_damage_rect->Union(quad_rectangle);
|
| + }
|
| + } else {
|
| + // Entire replacement quad must be redrawn.
|
| + damage_rect->Union(quad_rectangle);
|
| + }
|
| + previous_occlusion_bounding_box_ =
|
| + gfx::ToEnclosingRect(occlusion_bounding_box);
|
| + }
|
| +
|
| + ca_layer_overlays->push_back(ca_layer);
|
| + // Only allow one overlay for now.
|
| + break;
|
| + }
|
| + previous_frame_underlay_rect_ = this_frame_underlay_rect;
|
| +}
|
| +
|
| +} // namespace cc
|
|
|