summaryrefslogtreecommitdiffstats
path: root/cc/output/overlay_processor.cc
blob: 74e68d22cd0373279b7bc26add8cad7d17ff8e36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 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