1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/viz/service/display/overlay_processor_surface_control.h"
6 
7 #include "components/viz/service/display/overlay_strategy_underlay.h"
8 #include "ui/gfx/geometry/rect_conversions.h"
9 #include "ui/gfx/overlay_transform_utils.h"
10 #include "ui/gl/android/android_surface_control_compat.h"
11 
12 namespace viz {
13 namespace {
14 
ClipFromOrigin(gfx::RectF input)15 gfx::RectF ClipFromOrigin(gfx::RectF input) {
16   if (input.x() < 0.f) {
17     input.set_width(input.width() + input.x());
18     input.set_x(0.f);
19   }
20 
21   if (input.y() < 0) {
22     input.set_height(input.height() + input.y());
23     input.set_y(0.f);
24   }
25 
26   return input;
27 }
28 
29 }  // namespace
30 
OverlayProcessorSurfaceControl(bool enable_overlay)31 OverlayProcessorSurfaceControl::OverlayProcessorSurfaceControl(
32     bool enable_overlay)
33     : OverlayProcessorUsingStrategy(), overlay_enabled_(enable_overlay) {
34   if (overlay_enabled_) {
35     strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
36         this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
37   }
38 }
39 
~OverlayProcessorSurfaceControl()40 OverlayProcessorSurfaceControl::~OverlayProcessorSurfaceControl() {}
41 
IsOverlaySupported() const42 bool OverlayProcessorSurfaceControl::IsOverlaySupported() const {
43   return overlay_enabled_;
44 }
45 
NeedsSurfaceOccludingDamageRect() const46 bool OverlayProcessorSurfaceControl::NeedsSurfaceOccludingDamageRect() const {
47   return true;
48 }
49 
CheckOverlaySupport(const OverlayProcessorInterface::OutputSurfaceOverlayPlane * primary_plane,OverlayCandidateList * candidates)50 void OverlayProcessorSurfaceControl::CheckOverlaySupport(
51     const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
52     OverlayCandidateList* candidates) {
53   DCHECK(!candidates->empty());
54 
55   for (auto& candidate : *candidates) {
56     if (!gl::SurfaceControl::SupportsColorSpace(candidate.color_space)) {
57       candidate.overlay_handled = false;
58       return;
59     }
60 
61     // Check if screen rotation matches.
62     if (candidate.transform != display_transform_) {
63       candidate.overlay_handled = false;
64       return;
65     }
66     candidate.transform = gfx::OVERLAY_TRANSFORM_NONE;
67 
68     gfx::RectF orig_display_rect = candidate.display_rect;
69     gfx::RectF display_rect = orig_display_rect;
70     if (candidate.is_clipped)
71       display_rect.Intersect(gfx::RectF(candidate.clip_rect));
72     // The framework doesn't support display rects positioned at a negative
73     // offset.
74     display_rect = ClipFromOrigin(display_rect);
75     if (display_rect.IsEmpty()) {
76       candidate.overlay_handled = false;
77       return;
78     }
79 
80     // The display rect above includes the |display_transform_| while the rects
81     // sent to the platform API need to be in the logical screen space.
82     const gfx::Transform display_inverse = gfx::OverlayTransformToTransform(
83         gfx::InvertOverlayTransform(display_transform_),
84         gfx::SizeF(viewport_size_));
85     display_inverse.TransformRect(&orig_display_rect);
86     display_inverse.TransformRect(&display_rect);
87 
88     candidate.display_rect = gfx::RectF(gfx::ToEnclosingRect(display_rect));
89     candidate.uv_rect = cc::MathUtil::ScaleRectProportional(
90         candidate.uv_rect, orig_display_rect, candidate.display_rect);
91     candidate.overlay_handled = true;
92   }
93 }
94 
AdjustOutputSurfaceOverlay(base::Optional<OutputSurfaceOverlayPlane> * output_surface_plane)95 void OverlayProcessorSurfaceControl::AdjustOutputSurfaceOverlay(
96     base::Optional<OutputSurfaceOverlayPlane>* output_surface_plane) {
97   // For surface control, we should always have a valid |output_surface_plane|
98   // here.
99   DCHECK(output_surface_plane && output_surface_plane->has_value());
100 
101   OutputSurfaceOverlayPlane& plane = output_surface_plane->value();
102   DCHECK(gl::SurfaceControl::SupportsColorSpace(plane.color_space))
103       << "The main overlay must only use color space supported by the "
104          "device";
105 
106   DCHECK_EQ(plane.transform, gfx::OVERLAY_TRANSFORM_NONE);
107   DCHECK(plane.display_rect == ClipFromOrigin(plane.display_rect));
108 
109   plane.transform = display_transform_;
110   const gfx::Transform display_inverse = gfx::OverlayTransformToTransform(
111       gfx::InvertOverlayTransform(display_transform_),
112       gfx::SizeF(viewport_size_));
113   display_inverse.TransformRect(&plane.display_rect);
114   plane.display_rect = gfx::RectF(gfx::ToEnclosingRect(plane.display_rect));
115 
116   // Call the base class implementation.
117   OverlayProcessorUsingStrategy::AdjustOutputSurfaceOverlay(
118       output_surface_plane);
119 }
120 
GetOverlayDamageRectForOutputSurface(const OverlayCandidate & candidate) const121 gfx::Rect OverlayProcessorSurfaceControl::GetOverlayDamageRectForOutputSurface(
122     const OverlayCandidate& candidate) const {
123   // Should only be called after ProcessForOverlays on handled candidates.
124   DCHECK(candidate.overlay_handled);
125   // We transform the candidate's display rect to the logical screen space (used
126   // by the ui when preparing the frame) that the SurfaceControl expects it to
127   // be in. So in order to provide a damage rect which maps to the
128   // OutputSurface's main plane, we need to undo that transformation. But only
129   // if the overlay is in handled state, since the modification above is only
130   // applied when we mark the overlay as handled.
131   gfx::Size viewport_size_pre_display_transform(viewport_size_.height(),
132                                                 viewport_size_.width());
133   auto transform = gfx::OverlayTransformToTransform(
134       display_transform_, gfx::SizeF(viewport_size_pre_display_transform));
135   gfx::RectF transformed_rect(candidate.display_rect);
136   transform.TransformRect(&transformed_rect);
137   return gfx::ToEnclosedRect(transformed_rect);
138 }
139 
SetDisplayTransformHint(gfx::OverlayTransform transform)140 void OverlayProcessorSurfaceControl::SetDisplayTransformHint(
141     gfx::OverlayTransform transform) {
142   display_transform_ = transform;
143 }
144 
SetViewportSize(const gfx::Size & viewport_size)145 void OverlayProcessorSurfaceControl::SetViewportSize(
146     const gfx::Size& viewport_size) {
147   viewport_size_ = viewport_size;
148 }
149 
150 }  // namespace viz
151