1 // Copyright 2014 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/display.h"
6 
7 #include <stddef.h>
8 #include <limits>
9 
10 #include "base/debug/dump_without_crashing.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/optional.h"
13 #include "base/stl_util.h"
14 #include "base/timer/elapsed_timer.h"
15 #include "base/trace_event/trace_event.h"
16 #include "build/build_config.h"
17 #include "cc/base/region.h"
18 #include "cc/base/simple_enclosed_region.h"
19 #include "cc/benchmarks/benchmark_instrumentation.h"
20 #include "components/viz/common/display/renderer_settings.h"
21 #include "components/viz/common/features.h"
22 #include "components/viz/common/frame_sinks/begin_frame_source.h"
23 #include "components/viz/common/quads/compositor_frame.h"
24 #include "components/viz/common/quads/draw_quad.h"
25 #include "components/viz/common/quads/shared_quad_state.h"
26 #include "components/viz/service/display/damage_frame_annotator.h"
27 #include "components/viz/service/display/direct_renderer.h"
28 #include "components/viz/service/display/display_client.h"
29 #include "components/viz/service/display/display_scheduler.h"
30 #include "components/viz/service/display/gl_renderer.h"
31 #include "components/viz/service/display/output_surface.h"
32 #include "components/viz/service/display/renderer_utils.h"
33 #include "components/viz/service/display/skia_output_surface.h"
34 #include "components/viz/service/display/skia_renderer.h"
35 #include "components/viz/service/display/software_renderer.h"
36 #include "components/viz/service/display/surface_aggregator.h"
37 #include "components/viz/service/surfaces/surface.h"
38 #include "components/viz/service/surfaces/surface_manager.h"
39 #include "gpu/command_buffer/client/gles2_interface.h"
40 #include "gpu/ipc/scheduler_sequence.h"
41 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
42 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.h"
43 #include "ui/gfx/buffer_types.h"
44 #include "ui/gfx/geometry/rect_conversions.h"
45 #include "ui/gfx/overlay_transform_utils.h"
46 #include "ui/gfx/presentation_feedback.h"
47 #include "ui/gfx/swap_result.h"
48 
49 namespace viz {
50 
51 namespace {
52 
53 const DrawQuad::Material kNonSplittableMaterials[] = {
54     // Exclude debug quads from quad splitting
55     DrawQuad::Material::kDebugBorder,
56     // Exclude possible overlay candidates from quad splitting
57     // See OverlayCandidate::FromDrawQuad
58     DrawQuad::Material::kStreamVideoContent,
59     DrawQuad::Material::kTextureContent,
60     DrawQuad::Material::kVideoHole,
61     // See DCLayerOverlayProcessor::ProcessRenderPass
62     DrawQuad::Material::kYuvVideoContent,
63 };
64 
65 constexpr base::TimeDelta kAllowedDeltaFromFuture =
66     base::TimeDelta::FromMilliseconds(16);
67 
68 // Assign each Display instance a starting value for the the display-trace id,
69 // so that multiple Displays all don't start at 0, because that makes it
70 // difficult to associate the trace-events with the particular displays.
GetStartingTraceId()71 int64_t GetStartingTraceId() {
72   static int64_t client = 0;
73   // https://crbug.com/956695
74   return ((++client & 0xffff) << 16);
75 }
76 
SanitizePresentationFeedback(const gfx::PresentationFeedback & feedback,base::TimeTicks draw_time)77 gfx::PresentationFeedback SanitizePresentationFeedback(
78     const gfx::PresentationFeedback& feedback,
79     base::TimeTicks draw_time) {
80   // Temporary to investigate large presentation times.
81   // https://crbug.com/894440
82   DCHECK(!draw_time.is_null());
83   if (feedback.timestamp.is_null())
84     return feedback;
85 
86   // If the presentation-timestamp is from the future, or from the past (i.e.
87   // before swap-time), then invalidate the feedback. Also report how far into
88   // the future (or from the past) the timestamps are.
89   // https://crbug.com/894440
90   const auto now = base::TimeTicks::Now();
91   // The timestamp for the presentation feedback may have a different source and
92   // therefore the timestamp can be slightly in the future in comparison with
93   // base::TimeTicks::Now(). Such presentation feedbacks should not be rejected.
94   // See https://crbug.com/1040178
95   const auto allowed_delta_from_future =
96       ((feedback.flags & gfx::PresentationFeedback::kHWClock) != 0)
97           ? kAllowedDeltaFromFuture
98           : base::TimeDelta();
99   if (feedback.timestamp > now + allowed_delta_from_future) {
100     const auto diff = feedback.timestamp - now;
101     UMA_HISTOGRAM_MEDIUM_TIMES(
102         "Graphics.PresentationTimestamp.InvalidFromFuture", diff);
103     return gfx::PresentationFeedback::Failure();
104   }
105 
106   if (feedback.timestamp < draw_time) {
107     const auto diff = draw_time - feedback.timestamp;
108     UMA_HISTOGRAM_MEDIUM_TIMES(
109         "Graphics.PresentationTimestamp.InvalidBeforeSwap", diff);
110     return gfx::PresentationFeedback::Failure();
111   }
112 
113 #ifndef TOOLKIT_QT
114   const auto difference = feedback.timestamp - draw_time;
115   if (difference.InMinutes() > 3) {
116     UMA_HISTOGRAM_CUSTOM_TIMES(
117         "Graphics.PresentationTimestamp.LargePresentationDelta", difference,
118         base::TimeDelta::FromMinutes(3), base::TimeDelta::FromHours(1), 50);
119   }
120 #endif
121   return feedback;
122 }
123 
124 // Returns the bounds for the largest rect that can be inscribed in a rounded
125 // rect.
GetOccludingRectForRRectF(const gfx::RRectF & bounds)126 gfx::RectF GetOccludingRectForRRectF(const gfx::RRectF& bounds) {
127   if (bounds.IsEmpty())
128     return gfx::RectF();
129   if (bounds.GetType() == gfx::RRectF::Type::kRect)
130     return bounds.rect();
131   gfx::RectF occluding_rect = bounds.rect();
132 
133   // Compute the radius for each corner
134   float top_left = bounds.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).x();
135   float top_right = bounds.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).x();
136   float lower_right =
137       bounds.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).x();
138   float lower_left = bounds.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x();
139 
140   // Get a bounding rect that does not intersect with the rounding clip.
141   // When a rect has rounded corner with radius r, then the largest rect that
142   // can be inscribed inside it has an inset of |((2 - sqrt(2)) / 2) * radius|.
143   occluding_rect.Inset(std::max(top_left, lower_left) * 0.3f,
144                        std::max(top_left, top_right) * 0.3f,
145                        std::max(top_right, lower_right) * 0.3f,
146                        std::max(lower_right, lower_left) * 0.3f);
147   return occluding_rect;
148 }
149 
150 // SkRegion uses INT_MAX as a sentinel. Reduce gfx::Rect values when they are
151 // equal to INT_MAX to prevent conversion to an empty region.
SafeConvertRectForRegion(const gfx::Rect & r)152 gfx::Rect SafeConvertRectForRegion(const gfx::Rect& r) {
153   gfx::Rect safe_rect(r);
154   if (safe_rect.x() == INT_MAX)
155     safe_rect.set_x(INT_MAX - 1);
156   if (safe_rect.y() == INT_MAX)
157     safe_rect.set_y(INT_MAX - 1);
158   if (safe_rect.width() == INT_MAX)
159     safe_rect.set_width(INT_MAX - 1);
160   if (safe_rect.height() == INT_MAX)
161     safe_rect.set_height(INT_MAX - 1);
162   return safe_rect;
163 }
164 
165 // Computes the accumulated area of all the rectangles in the list of |rects|.
ComputeArea(const std::vector<gfx::Rect> & rects)166 int ComputeArea(const std::vector<gfx::Rect>& rects) {
167   int area = 0;
168   for (const auto& r : rects)
169     area += r.size().GetArea();
170   return area;
171 }
172 
173 // Decides whether or not a DrawQuad should be split into a more complex visible
174 // region in order to avoid overdraw.
CanSplitQuad(const DrawQuad::Material m,const int visible_region_area,const int visible_region_bounding_area,const int minimum_fragments_reduced,const float device_scale_factor)175 bool CanSplitQuad(const DrawQuad::Material m,
176                   const int visible_region_area,
177                   const int visible_region_bounding_area,
178                   const int minimum_fragments_reduced,
179                   const float device_scale_factor) {
180   return !base::Contains(kNonSplittableMaterials, m) &&
181          (visible_region_bounding_area - visible_region_area) *
182                  device_scale_factor * device_scale_factor >
183              minimum_fragments_reduced;
184 }
185 
186 // Attempts to consolidate rectangles that were only split because of the
187 // nature of base::Region and transforms the region into a list of visible
188 // rectangles. Returns true upon successful reduction of the region to under
189 // |complexity_limit|, false otherwise.
ReduceComplexity(const cc::Region & region,size_t complexity_limit,std::vector<gfx::Rect> * reduced_region)190 bool ReduceComplexity(const cc::Region& region,
191                       size_t complexity_limit,
192                       std::vector<gfx::Rect>* reduced_region) {
193   DCHECK(reduced_region);
194 
195   reduced_region->clear();
196   for (const gfx::Rect& r : region) {
197     auto it =
198         std::find_if(reduced_region->begin(), reduced_region->end(),
199                      [&r](const gfx::Rect& a) { return a.SharesEdgeWith(r); });
200     if (it != reduced_region->end()) {
201       it->Union(r);
202       continue;
203     }
204     reduced_region->push_back(r);
205 
206     if (reduced_region->size() >= complexity_limit)
207       return false;
208   }
209   return true;
210 }
211 
212 }  // namespace
213 
214 constexpr base::TimeDelta Display::kDrawToSwapMin;
215 constexpr base::TimeDelta Display::kDrawToSwapMax;
216 
217 Display::PresentationGroupTiming::PresentationGroupTiming() = default;
218 
219 Display::PresentationGroupTiming::PresentationGroupTiming(
220     Display::PresentationGroupTiming&& other) = default;
221 
222 Display::PresentationGroupTiming::~PresentationGroupTiming() = default;
223 
AddPresentationHelper(std::unique_ptr<Surface::PresentationHelper> helper)224 void Display::PresentationGroupTiming::AddPresentationHelper(
225     std::unique_ptr<Surface::PresentationHelper> helper) {
226   presentation_helpers_.push_back(std::move(helper));
227 }
228 
OnDraw(base::TimeTicks draw_start_timestamp)229 void Display::PresentationGroupTiming::OnDraw(
230     base::TimeTicks draw_start_timestamp) {
231   draw_start_timestamp_ = draw_start_timestamp;
232 }
233 
OnSwap(gfx::SwapTimings timings)234 void Display::PresentationGroupTiming::OnSwap(gfx::SwapTimings timings) {
235   swap_timings_ = timings;
236 }
237 
OnPresent(const gfx::PresentationFeedback & feedback)238 void Display::PresentationGroupTiming::OnPresent(
239     const gfx::PresentationFeedback& feedback) {
240   for (auto& presentation_helper : presentation_helpers_) {
241     presentation_helper->DidPresent(draw_start_timestamp_, swap_timings_,
242                                     feedback);
243   }
244 }
245 
Display(SharedBitmapManager * bitmap_manager,const RendererSettings & settings,const FrameSinkId & frame_sink_id,std::unique_ptr<OutputSurface> output_surface,std::unique_ptr<OverlayProcessorInterface> overlay_processor,std::unique_ptr<DisplaySchedulerBase> scheduler,scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)246 Display::Display(
247     SharedBitmapManager* bitmap_manager,
248     const RendererSettings& settings,
249     const FrameSinkId& frame_sink_id,
250     std::unique_ptr<OutputSurface> output_surface,
251     std::unique_ptr<OverlayProcessorInterface> overlay_processor,
252     std::unique_ptr<DisplaySchedulerBase> scheduler,
253     scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
254     : bitmap_manager_(bitmap_manager),
255       settings_(settings),
256       frame_sink_id_(frame_sink_id),
257       output_surface_(std::move(output_surface)),
258       skia_output_surface_(output_surface_->AsSkiaOutputSurface()),
259       scheduler_(std::move(scheduler)),
260       current_task_runner_(std::move(current_task_runner)),
261       overlay_processor_(std::move(overlay_processor)),
262       swapped_trace_id_(GetStartingTraceId()),
263       last_swap_ack_trace_id_(swapped_trace_id_),
264       last_presented_trace_id_(swapped_trace_id_) {
265   DCHECK(output_surface_);
266   DCHECK(frame_sink_id_.is_valid());
267   if (scheduler_)
268     scheduler_->SetClient(this);
269   enable_quad_splitting_ = features::ShouldSplitPartiallyOccludedQuads() &&
270                            !overlay_processor_->DisableSplittingQuads();
271 }
272 
~Display()273 Display::~Display() {
274 #if DCHECK_IS_ON()
275   allow_schedule_gpu_task_during_destruction_.reset(
276       new gpu::ScopedAllowScheduleGpuTask);
277 #endif
278 #if defined(OS_ANDROID)
279   // In certain cases, drivers hang when tearing down the display. Finishing
280   // before teardown appears to address this. As we're during display teardown,
281   // an additional finish should have minimal impact.
282   // TODO(ericrk): Add a more robust workaround. crbug.com/899705
283   if (auto* context = output_surface_->context_provider()) {
284     context->ContextGL()->Finish();
285   }
286 #endif
287 
288   if (no_pending_swaps_callback_)
289     std::move(no_pending_swaps_callback_).Run();
290 
291   for (auto& observer : observers_)
292     observer.OnDisplayDestroyed();
293   observers_.Clear();
294 
295   // Send gfx::PresentationFeedback::Failure() to any surfaces expecting
296   // feedback.
297   pending_presentation_group_timings_.clear();
298 
299   // Only do this if Initialize() happened.
300   if (client_) {
301     if (auto* context = output_surface_->context_provider())
302       context->RemoveObserver(this);
303     if (skia_output_surface_)
304       skia_output_surface_->RemoveContextLostObserver(this);
305   }
306 
307   // Un-register as DisplaySchedulerClient to prevent us from being called in a
308   // partially destructed state.
309   if (scheduler_)
310     scheduler_->SetClient(nullptr);
311 
312   if (damage_tracker_)
313     damage_tracker_->RunDrawCallbacks();
314 }
315 
Initialize(DisplayClient * client,SurfaceManager * surface_manager,bool enable_shared_images,bool using_synthetic_bfs)316 void Display::Initialize(DisplayClient* client,
317                          SurfaceManager* surface_manager,
318                          bool enable_shared_images,
319                          bool using_synthetic_bfs) {
320   DCHECK(client);
321   DCHECK(surface_manager);
322   gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
323   client_ = client;
324   surface_manager_ = surface_manager;
325 
326   output_surface_->BindToClient(this);
327   if (output_surface_->software_device())
328     output_surface_->software_device()->BindToClient(this);
329 
330   frame_rate_decider_ = std::make_unique<FrameRateDecider>(
331       surface_manager_, this, using_synthetic_bfs);
332 
333   InitializeRenderer(enable_shared_images);
334 
335   damage_tracker_ = std::make_unique<DisplayDamageTracker>(surface_manager_,
336                                                            aggregator_.get());
337   if (scheduler_)
338     scheduler_->SetDamageTracker(damage_tracker_.get());
339 
340   // This depends on assumptions that Display::Initialize will happen on the
341   // same callstack as the ContextProvider being created/initialized or else
342   // it could miss a callback before setting this.
343   if (auto* context = output_surface_->context_provider())
344     context->AddObserver(this);
345 
346   if (skia_output_surface_)
347     skia_output_surface_->AddContextLostObserver(this);
348 }
349 
AddObserver(DisplayObserver * observer)350 void Display::AddObserver(DisplayObserver* observer) {
351   observers_.AddObserver(observer);
352 }
353 
RemoveObserver(DisplayObserver * observer)354 void Display::RemoveObserver(DisplayObserver* observer) {
355   observers_.RemoveObserver(observer);
356 }
357 
SetLocalSurfaceId(const LocalSurfaceId & id,float device_scale_factor)358 void Display::SetLocalSurfaceId(const LocalSurfaceId& id,
359                                 float device_scale_factor) {
360   if (current_surface_id_.local_surface_id() == id &&
361       device_scale_factor_ == device_scale_factor) {
362     return;
363   }
364 
365   TRACE_EVENT0("viz", "Display::SetSurfaceId");
366   current_surface_id_ = SurfaceId(frame_sink_id_, id);
367   device_scale_factor_ = device_scale_factor;
368 
369   damage_tracker_->SetNewRootSurface(current_surface_id_);
370 }
371 
SetVisible(bool visible)372 void Display::SetVisible(bool visible) {
373   TRACE_EVENT1("viz", "Display::SetVisible", "visible", visible);
374   if (renderer_)
375     renderer_->SetVisible(visible);
376   if (scheduler_)
377     scheduler_->SetVisible(visible);
378   visible_ = visible;
379 
380   if (!visible) {
381     // Damage tracker needs a full reset as renderer resources are dropped when
382     // not visible.
383     if (aggregator_ && current_surface_id_.is_valid())
384       aggregator_->SetFullDamageForSurface(current_surface_id_);
385   }
386 }
387 
Resize(const gfx::Size & size)388 void Display::Resize(const gfx::Size& size) {
389   disable_swap_until_resize_ = false;
390 
391   if (size == current_surface_size_)
392     return;
393 
394   // This DCHECK should probably go at the top of the function, but mac
395   // sometimes calls Resize() with 0x0 before it sets a real size. This will
396   // early out before the DCHECK fails.
397   DCHECK(!size.IsEmpty());
398   TRACE_EVENT0("viz", "Display::Resize");
399 
400   swapped_since_resize_ = false;
401   current_surface_size_ = size;
402 
403   damage_tracker_->DisplayResized();
404 }
405 
DisableSwapUntilResize(base::OnceClosure no_pending_swaps_callback)406 void Display::DisableSwapUntilResize(
407     base::OnceClosure no_pending_swaps_callback) {
408   TRACE_EVENT0("viz", "Display::DisableSwapUntilResize");
409   DCHECK(no_pending_swaps_callback_.is_null());
410 
411   if (!disable_swap_until_resize_) {
412     DCHECK(scheduler_);
413 
414     if (!swapped_since_resize_)
415       scheduler_->ForceImmediateSwapIfPossible();
416 
417     if (no_pending_swaps_callback && pending_swaps_ > 0 &&
418         (output_surface_->context_provider() ||
419          output_surface_->AsSkiaOutputSurface())) {
420       no_pending_swaps_callback_ = std::move(no_pending_swaps_callback);
421     }
422 
423     disable_swap_until_resize_ = true;
424   }
425 
426   // There are no pending swaps for current size so immediately run callback.
427   if (no_pending_swaps_callback)
428     std::move(no_pending_swaps_callback).Run();
429 }
430 
SetColorMatrix(const SkMatrix44 & matrix)431 void Display::SetColorMatrix(const SkMatrix44& matrix) {
432   if (output_surface_)
433     output_surface_->set_color_matrix(matrix);
434 
435   // Force a redraw.
436   if (aggregator_) {
437     if (current_surface_id_.is_valid())
438       aggregator_->SetFullDamageForSurface(current_surface_id_);
439   }
440 
441   damage_tracker_->SetRootSurfaceDamaged();
442 }
443 
SetDisplayColorSpaces(const gfx::DisplayColorSpaces & display_color_spaces)444 void Display::SetDisplayColorSpaces(
445     const gfx::DisplayColorSpaces& display_color_spaces) {
446   display_color_spaces_ = display_color_spaces;
447   if (aggregator_)
448     aggregator_->SetDisplayColorSpaces(display_color_spaces_);
449 }
450 
SetOutputIsSecure(bool secure)451 void Display::SetOutputIsSecure(bool secure) {
452   if (secure == output_is_secure_)
453     return;
454   output_is_secure_ = secure;
455 
456   if (aggregator_) {
457     aggregator_->set_output_is_secure(secure);
458     // Force a redraw.
459     if (current_surface_id_.is_valid())
460       aggregator_->SetFullDamageForSurface(current_surface_id_);
461   }
462 }
463 
InitializeRenderer(bool enable_shared_images)464 void Display::InitializeRenderer(bool enable_shared_images) {
465   auto mode = output_surface_->context_provider() || skia_output_surface_
466                   ? DisplayResourceProvider::kGpu
467                   : DisplayResourceProvider::kSoftware;
468   resource_provider_ = std::make_unique<DisplayResourceProvider>(
469       mode, output_surface_->context_provider(), bitmap_manager_,
470       enable_shared_images);
471   if (settings_.use_skia_renderer && mode == DisplayResourceProvider::kGpu) {
472     // Default to use DDL if skia_output_surface is not null.
473     if (skia_output_surface_) {
474       renderer_ = std::make_unique<SkiaRenderer>(
475           &settings_, output_surface_.get(), resource_provider_.get(),
476           overlay_processor_.get(), skia_output_surface_,
477           SkiaRenderer::DrawMode::DDL);
478     } else {
479       // GPU compositing with GL to an SKP.
480       DCHECK(output_surface_);
481       DCHECK(output_surface_->context_provider());
482       DCHECK(settings_.record_sk_picture);
483       DCHECK(!overlay_processor_->IsOverlaySupported());
484       renderer_ = std::make_unique<SkiaRenderer>(
485           &settings_, output_surface_.get(), resource_provider_.get(),
486           overlay_processor_.get(), nullptr /* skia_output_surface */,
487           SkiaRenderer::DrawMode::SKPRECORD);
488     }
489   } else if (output_surface_->context_provider()) {
490     renderer_ = std::make_unique<GLRenderer>(
491         &settings_, output_surface_.get(), resource_provider_.get(),
492         overlay_processor_.get(), current_task_runner_);
493   } else {
494     DCHECK(!overlay_processor_->IsOverlaySupported());
495     auto renderer = std::make_unique<SoftwareRenderer>(
496         &settings_, output_surface_.get(), resource_provider_.get(),
497         overlay_processor_.get());
498     software_renderer_ = renderer.get();
499     renderer_ = std::move(renderer);
500   }
501 
502   renderer_->Initialize();
503   renderer_->SetVisible(visible_);
504 
505   // Outputting a partial list of quads might not work in cases where contents
506   // outside the damage rect might be needed by the renderer.
507   bool output_partial_list =
508       output_surface_->capabilities().only_invalidates_damage_rect &&
509       renderer_->use_partial_swap() &&
510       !overlay_processor_->IsOverlaySupported();
511 
512   aggregator_ = std::make_unique<SurfaceAggregator>(
513       surface_manager_, resource_provider_.get(), output_partial_list,
514       overlay_processor_->NeedsSurfaceOccludingDamageRect());
515   if (settings_.show_aggregated_damage)
516     aggregator_->SetFrameAnnotator(std::make_unique<DamageFrameAnnotator>());
517 
518   aggregator_->set_output_is_secure(output_is_secure_);
519   aggregator_->SetDisplayColorSpaces(display_color_spaces_);
520   // Consider adding a softare limit as well.
521   aggregator_->SetMaximumTextureSize(
522       (output_surface_ && output_surface_->context_provider())
523           ? output_surface_->context_provider()
524                 ->ContextCapabilities()
525                 .max_texture_size
526           : 0);
527 }
528 
IsRootFrameMissing() const529 bool Display::IsRootFrameMissing() const {
530   return damage_tracker_->root_frame_missing();
531 }
532 
HasPendingSurfaces(const BeginFrameArgs & args) const533 bool Display::HasPendingSurfaces(const BeginFrameArgs& args) const {
534   return damage_tracker_->HasPendingSurfaces(args);
535 }
536 
OnContextLost()537 void Display::OnContextLost() {
538   if (scheduler_)
539     scheduler_->OutputSurfaceLost();
540   // WARNING: The client may delete the Display in this method call. Do not
541   // make any additional references to members after this call.
542   client_->DisplayOutputSurfaceLost();
543 }
544 
DrawAndSwap(base::TimeTicks expected_display_time)545 bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
546   TRACE_EVENT0("viz", "Display::DrawAndSwap");
547   gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
548 
549   if (!current_surface_id_.is_valid()) {
550     TRACE_EVENT_INSTANT0("viz", "No root surface.", TRACE_EVENT_SCOPE_THREAD);
551     return false;
552   }
553 
554   if (!output_surface_) {
555     TRACE_EVENT_INSTANT0("viz", "No output surface", TRACE_EVENT_SCOPE_THREAD);
556     return false;
557   }
558 
559   if (output_surface_->capabilities().skips_draw) {
560     TRACE_EVENT_INSTANT0("viz", "Skip draw", TRACE_EVENT_SCOPE_THREAD);
561     return true;
562   }
563 
564   gfx::OverlayTransform current_display_transform = gfx::OVERLAY_TRANSFORM_NONE;
565   Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id_);
566   if (surface->HasActiveFrame()) {
567     current_display_transform =
568         surface->GetActiveFrame().metadata.display_transform_hint;
569     if (current_display_transform != output_surface_->GetDisplayTransform()) {
570       output_surface_->SetDisplayTransformHint(current_display_transform);
571 
572       // Gets the transform from |output_surface_| back so that if it ignores
573       // the hint, the rest of the code ignores the hint too.
574       current_display_transform = output_surface_->GetDisplayTransform();
575     }
576   }
577 
578   // During aggregation, SurfaceAggregator marks all resources used for a draw
579   // in the resource provider.  This has the side effect of deleting unused
580   // resources and their textures, generating sync tokens, and returning the
581   // resources to the client.  This involves GL work which is issued before
582   // drawing commands, and gets prioritized by GPU scheduler because sync token
583   // dependencies aren't issued until the draw.
584   //
585   // Batch and defer returning resources in resource provider.  This defers the
586   // GL commands for deleting resources to after the draw, and prevents context
587   // switching because the scheduler knows sync token dependencies at that time.
588   DisplayResourceProvider::ScopedBatchReturnResources returner(
589       resource_provider_.get());
590   base::ElapsedTimer aggregate_timer;
591   aggregate_timer.Begin();
592   CompositorFrame frame;
593   {
594     FrameRateDecider::ScopedAggregate scoped_aggregate(
595         frame_rate_decider_.get());
596     frame =
597         aggregator_->Aggregate(current_surface_id_, expected_display_time,
598                                current_display_transform, ++swapped_trace_id_);
599   }
600 
601   UMA_HISTOGRAM_COUNTS_1M("Compositing.SurfaceAggregator.AggregateUs",
602                           aggregate_timer.Elapsed().InMicroseconds());
603 
604   if (frame.render_pass_list.empty()) {
605     TRACE_EVENT_INSTANT0("viz", "Empty aggregated frame.",
606                          TRACE_EVENT_SCOPE_THREAD);
607     return false;
608   }
609 
610   TRACE_EVENT_ASYNC_BEGIN0("viz,benchmark", "Graphics.Pipeline.DrawAndSwap",
611                            swapped_trace_id_);
612 
613   // Run callbacks early to allow pipelining and collect presented callbacks.
614   damage_tracker_->RunDrawCallbacks();
615 
616   frame.metadata.latency_info.insert(frame.metadata.latency_info.end(),
617                                      stored_latency_info_.begin(),
618                                      stored_latency_info_.end());
619   stored_latency_info_.clear();
620   bool have_copy_requests = false;
621   for (const auto& pass : frame.render_pass_list)
622     have_copy_requests |= !pass->copy_requests.empty();
623 
624   gfx::Size surface_size;
625   bool have_damage = false;
626   auto& last_render_pass = *frame.render_pass_list.back();
627 
628   // The CompositorFrame provided by the SurfaceAggregator includes the display
629   // transform while |current_surface_size_| is the pre-transform size received
630   // from the client.
631   const gfx::Transform display_transform = gfx::OverlayTransformToTransform(
632       current_display_transform, gfx::SizeF(current_surface_size_));
633   const gfx::Size current_surface_size =
634       cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
635           display_transform, gfx::Rect(current_surface_size_))
636           .size();
637   if (settings_.auto_resize_output_surface &&
638       last_render_pass.output_rect.size() != current_surface_size &&
639       last_render_pass.damage_rect == last_render_pass.output_rect &&
640       !current_surface_size.IsEmpty()) {
641     // Resize the output rect to the current surface size so that we won't
642     // skip the draw and so that the GL swap won't stretch the output.
643     last_render_pass.output_rect.set_size(current_surface_size);
644     last_render_pass.damage_rect = last_render_pass.output_rect;
645   }
646   surface_size = last_render_pass.output_rect.size();
647   have_damage = !last_render_pass.damage_rect.size().IsEmpty();
648 
649   bool size_matches = surface_size == current_surface_size;
650   if (!size_matches)
651     TRACE_EVENT_INSTANT0("viz", "Size mismatch.", TRACE_EVENT_SCOPE_THREAD);
652 
653   bool should_draw = have_copy_requests || (have_damage && size_matches);
654   client_->DisplayWillDrawAndSwap(should_draw, &frame.render_pass_list);
655 
656   base::Optional<base::ElapsedTimer> draw_timer;
657   if (should_draw) {
658     TRACE_EVENT_ASYNC_STEP_INTO0("viz,benchmark",
659                                  "Graphics.Pipeline.DrawAndSwap",
660                                  swapped_trace_id_, "Draw");
661     base::ElapsedTimer draw_occlusion_timer;
662     RemoveOverdrawQuads(&frame);
663     UMA_HISTOGRAM_COUNTS_1000(
664         "Compositing.Display.Draw.Occlusion.Calculation.Time",
665         draw_occlusion_timer.Elapsed().InMicroseconds());
666 
667     bool disable_image_filtering =
668         frame.metadata.is_resourceless_software_draw_with_scroll_or_animation;
669     if (software_renderer_) {
670       software_renderer_->SetDisablePictureQuadImageFiltering(
671           disable_image_filtering);
672     } else {
673       // This should only be set for software draws in synchronous compositor.
674       DCHECK(!disable_image_filtering);
675     }
676 
677     draw_timer.emplace();
678     renderer_->DecideRenderPassAllocationsForFrame(frame.render_pass_list);
679     renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_,
680                          current_surface_size, display_color_spaces_);
681     switch (output_surface_->type()) {
682       case OutputSurface::Type::kSoftware:
683         UMA_HISTOGRAM_COUNTS_1M(
684             "Compositing.DirectRenderer.Software.DrawFrameUs",
685             draw_timer->Elapsed().InMicroseconds());
686         break;
687       case OutputSurface::Type::kOpenGL:
688         UMA_HISTOGRAM_COUNTS_1M("Compositing.DirectRenderer.GL.DrawFrameUs",
689                                 draw_timer->Elapsed().InMicroseconds());
690         break;
691       case OutputSurface::Type::kVulkan:
692         UMA_HISTOGRAM_COUNTS_1M("Compositing.DirectRenderer.VK.DrawFrameUs",
693                                 draw_timer->Elapsed().InMicroseconds());
694         break;
695     }
696   } else {
697     TRACE_EVENT_INSTANT0("viz", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD);
698   }
699 
700   bool should_swap = !disable_swap_until_resize_ && should_draw && size_matches;
701   if (should_swap) {
702     PresentationGroupTiming presentation_group_timing;
703     presentation_group_timing.OnDraw(draw_timer->Begin());
704 
705     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
706       Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
707       if (surface) {
708         std::unique_ptr<Surface::PresentationHelper> helper =
709             surface->TakePresentationHelperForPresentNotification();
710         if (helper) {
711           presentation_group_timing.AddPresentationHelper(std::move(helper));
712         }
713       }
714     }
715     pending_presentation_group_timings_.emplace_back(
716         std::move(presentation_group_timing));
717 
718     TRACE_EVENT_ASYNC_STEP_INTO0("viz,benchmark",
719                                  "Graphics.Pipeline.DrawAndSwap",
720                                  swapped_trace_id_, "WaitForSwap");
721     swapped_since_resize_ = true;
722 
723     ui::LatencyInfo::TraceIntermediateFlowEvents(
724         frame.metadata.latency_info,
725         perfetto::protos::pbzero::ChromeLatencyInfo::STEP_DRAW_AND_SWAP);
726 
727     cc::benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
728     DirectRenderer::SwapFrameData swap_frame_data;
729     swap_frame_data.latency_info = std::move(frame.metadata.latency_info);
730     if (frame.metadata.top_controls_visible_height.has_value()) {
731       swap_frame_data.top_controls_visible_height_changed =
732           last_top_controls_visible_height_ !=
733           *frame.metadata.top_controls_visible_height;
734       last_top_controls_visible_height_ =
735           *frame.metadata.top_controls_visible_height;
736     }
737 
738     // We must notify scheduler and increase |pending_swaps_| before calling
739     // SwapBuffers() as it can call DidReceiveSwapBuffersAck synchronously.
740     if (scheduler_)
741       scheduler_->DidSwapBuffers();
742     pending_swaps_++;
743 
744     renderer_->SwapBuffers(std::move(swap_frame_data));
745   } else {
746     TRACE_EVENT_INSTANT0("viz", "Swap skipped.", TRACE_EVENT_SCOPE_THREAD);
747 
748     if (have_damage && !size_matches)
749       aggregator_->SetFullDamageForSurface(current_surface_id_);
750 
751     if (have_damage) {
752       // Do not store more than the allowed size.
753       if (ui::LatencyInfo::Verify(frame.metadata.latency_info,
754                                   "Display::DrawAndSwap")) {
755         stored_latency_info_.swap(frame.metadata.latency_info);
756       }
757     } else {
758       // There was no damage. Terminate the latency info objects.
759       while (!frame.metadata.latency_info.empty()) {
760         auto& latency = frame.metadata.latency_info.back();
761         latency.Terminate();
762         frame.metadata.latency_info.pop_back();
763       }
764     }
765 
766     renderer_->SwapBuffersSkipped();
767 
768     TRACE_EVENT_ASYNC_END1("viz,benchmark", "Graphics.Pipeline.DrawAndSwap",
769                            swapped_trace_id_, "status", "canceled");
770     --swapped_trace_id_;
771     if (scheduler_) {
772       scheduler_->DidSwapBuffers();
773       scheduler_->DidReceiveSwapBuffersAck();
774     }
775   }
776 
777   client_->DisplayDidDrawAndSwap();
778 
779   // Garbage collection can lead to sync IPCs to the GPU service to verify sync
780   // tokens. We defer garbage collection until the end of DrawAndSwap to avoid
781   // stalling the critical path for compositing.
782   surface_manager_->GarbageCollectSurfaces();
783 
784   return true;
785 }
786 
DidReceiveSwapBuffersAck(const gfx::SwapTimings & timings)787 void Display::DidReceiveSwapBuffersAck(const gfx::SwapTimings& timings) {
788   // Adding to |pending_presentation_group_timings_| must
789   // have been done in DrawAndSwap(), and should not be popped until
790   // DidReceiveSwapBuffersAck.
791   DCHECK(!pending_presentation_group_timings_.empty());
792 
793   ++last_swap_ack_trace_id_;
794   TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
795       "viz,benchmark", "Graphics.Pipeline.DrawAndSwap", last_swap_ack_trace_id_,
796       "Swap", timings.swap_start);
797   TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
798       "viz,benchmark", "Graphics.Pipeline.DrawAndSwap", last_swap_ack_trace_id_,
799       "WaitForPresentation", timings.swap_end);
800 
801   DCHECK_GT(pending_swaps_, 0);
802   pending_swaps_--;
803   if (scheduler_) {
804     scheduler_->DidReceiveSwapBuffersAck();
805   }
806 
807   if (no_pending_swaps_callback_ && pending_swaps_ == 0)
808     std::move(no_pending_swaps_callback_).Run();
809 
810   if (overlay_processor_)
811     overlay_processor_->OverlayPresentationComplete();
812   if (renderer_)
813     renderer_->SwapBuffersComplete();
814 
815   // It's possible to receive multiple calls to DidReceiveSwapBuffersAck()
816   // before DidReceivePresentationFeedback(). Ensure that we're not setting
817   // |swap_timings_| for the same PresentationGroupTiming multiple times.
818   base::TimeTicks draw_start_timestamp;
819   for (auto& group_timing : pending_presentation_group_timings_) {
820     if (!group_timing.HasSwapped()) {
821       group_timing.OnSwap(timings);
822       draw_start_timestamp = group_timing.draw_start_timestamp();
823       break;
824     }
825   }
826 
827   // We should have at least one group that hasn't received a SwapBuffersAck
828   DCHECK(!draw_start_timestamp.is_null());
829 
830   // Check that the swap timings correspond with the timestamp from when
831   // the swap was triggered. Note that not all output surfaces provide timing
832   // information, hence the check for a valid swap_start.
833   if (!timings.swap_start.is_null()) {
834     DCHECK_LE(draw_start_timestamp, timings.swap_start);
835     base::TimeDelta delta = timings.swap_start - draw_start_timestamp;
836     UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
837         "Compositing.Display.DrawToSwapUs", delta, kDrawToSwapMin,
838         kDrawToSwapMax, kDrawToSwapUsBuckets);
839   }
840 }
841 
DidReceiveTextureInUseResponses(const gpu::TextureInUseResponses & responses)842 void Display::DidReceiveTextureInUseResponses(
843     const gpu::TextureInUseResponses& responses) {
844   if (renderer_)
845     renderer_->DidReceiveTextureInUseResponses(responses);
846 }
847 
DidReceiveCALayerParams(const gfx::CALayerParams & ca_layer_params)848 void Display::DidReceiveCALayerParams(
849     const gfx::CALayerParams& ca_layer_params) {
850   if (client_)
851     client_->DisplayDidReceiveCALayerParams(ca_layer_params);
852 }
853 
DidSwapWithSize(const gfx::Size & pixel_size)854 void Display::DidSwapWithSize(const gfx::Size& pixel_size) {
855   if (client_)
856     client_->DisplayDidCompleteSwapWithSize(pixel_size);
857 }
858 
DidReceivePresentationFeedback(const gfx::PresentationFeedback & feedback)859 void Display::DidReceivePresentationFeedback(
860     const gfx::PresentationFeedback& feedback) {
861   if (pending_presentation_group_timings_.empty()) {
862     DLOG(ERROR) << "Received unexpected PresentationFeedback";
863     return;
864   }
865   ++last_presented_trace_id_;
866   TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
867       "viz,benchmark", "Graphics.Pipeline.DrawAndSwap",
868       last_presented_trace_id_, feedback.timestamp);
869   auto& presentation_group_timing = pending_presentation_group_timings_.front();
870   auto copy_feedback = SanitizePresentationFeedback(
871       feedback, presentation_group_timing.draw_start_timestamp());
872   TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
873       "benchmark,viz", "Display::FrameDisplayed", TRACE_EVENT_SCOPE_THREAD,
874       copy_feedback.timestamp);
875   presentation_group_timing.OnPresent(copy_feedback);
876   pending_presentation_group_timings_.pop_front();
877 }
878 
SetNeedsRedrawRect(const gfx::Rect & damage_rect)879 void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
880   aggregator_->SetFullDamageForSurface(current_surface_id_);
881   damage_tracker_->SetRootSurfaceDamaged();
882 }
883 
DidFinishFrame(const BeginFrameAck & ack)884 void Display::DidFinishFrame(const BeginFrameAck& ack) {
885   for (auto& observer : observers_)
886     observer.OnDisplayDidFinishFrame(ack);
887 
888   // Only used with experimental de-jelly effect. Forces us to produce a new
889   // un-skewed frame if the last one had a de-jelly skew applied. This prevents
890   // de-jelly skew from staying on screen for more than one frame.
891   if (aggregator_->last_frame_had_jelly()) {
892     scheduler_->SetNeedsOneBeginFrame(true);
893   }
894 }
895 
CurrentSurfaceId()896 const SurfaceId& Display::CurrentSurfaceId() {
897   return current_surface_id_;
898 }
899 
GetSurfaceAtAggregation(const FrameSinkId & frame_sink_id) const900 LocalSurfaceId Display::GetSurfaceAtAggregation(
901     const FrameSinkId& frame_sink_id) const {
902   if (!aggregator_)
903     return LocalSurfaceId();
904   auto it = aggregator_->previous_contained_frame_sinks().find(frame_sink_id);
905   if (it == aggregator_->previous_contained_frame_sinks().end())
906     return LocalSurfaceId();
907   return it->second;
908 }
909 
SoftwareDeviceUpdatedCALayerParams(const gfx::CALayerParams & ca_layer_params)910 void Display::SoftwareDeviceUpdatedCALayerParams(
911     const gfx::CALayerParams& ca_layer_params) {
912   if (client_)
913     client_->DisplayDidReceiveCALayerParams(ca_layer_params);
914 }
915 
ForceImmediateDrawAndSwapIfPossible()916 void Display::ForceImmediateDrawAndSwapIfPossible() {
917   if (scheduler_)
918     scheduler_->ForceImmediateSwapIfPossible();
919 }
920 
SetNeedsOneBeginFrame()921 void Display::SetNeedsOneBeginFrame() {
922   if (scheduler_)
923     scheduler_->SetNeedsOneBeginFrame(false);
924 }
925 
RemoveOverdrawQuads(CompositorFrame * frame)926 void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
927   if (frame->render_pass_list.empty())
928     return;
929 
930   const SharedQuadState* last_sqs = nullptr;
931   cc::Region occlusion_in_target_space;
932   cc::Region backdrop_filters_in_target_space;
933   bool current_sqs_intersects_occlusion = false;
934 
935   base::flat_map<RenderPassId, gfx::Rect> backdrop_filter_rects;
936   for (const auto& pass : frame->render_pass_list) {
937     if (!pass->backdrop_filters.IsEmpty() &&
938         pass->backdrop_filters.HasFilterThatMovesPixels()) {
939       backdrop_filter_rects[pass->id] = cc::MathUtil::MapEnclosingClippedRect(
940           pass->transform_to_root_target, pass->output_rect);
941     }
942   }
943 
944   const auto& pass = frame->render_pass_list.back();
945   // TODO(yiyix): Add filter effects to draw occlusion calculation and perform
946   // draw occlusion on render pass.
947   if (!pass->filters.IsEmpty() || !pass->backdrop_filters.IsEmpty())
948     return;
949 
950   auto quad_list_end = pass->quad_list.end();
951   cc::Region occlusion_in_quad_content_space;
952   gfx::Rect render_pass_quads_in_content_space;
953   for (auto quad = pass->quad_list.begin(); quad != quad_list_end;) {
954     // Skip quad if it is a RenderPassDrawQuad because RenderPassDrawQuad is a
955     // special type of DrawQuad where the visible_rect of shared quad state is
956     // not entirely covered by draw quads in it.
957     if (quad->material == ContentDrawQuadBase::Material::kRenderPass) {
958       // A RenderPass with backdrop filters may apply to a quad underlying
959       // RenderPassQuad. These regions should be tracked so that correctly
960       // handle splitting and occlusion of the underlying quad.
961       auto it = backdrop_filter_rects.find(
962           RenderPassDrawQuad::MaterialCast(*quad)->render_pass_id);
963       if (it != backdrop_filter_rects.end()) {
964         backdrop_filters_in_target_space.Union(it->second);
965       }
966       ++quad;
967       continue;
968     }
969     // Also skip quad if the DrawQuad size is smaller than the
970     // kMinimumDrawOcclusionSize; or the DrawQuad is inside a 3d object.
971     if (quad->shared_quad_state->sorting_context_id != 0) {
972       ++quad;
973       continue;
974     }
975 
976     if (!last_sqs)
977       last_sqs = quad->shared_quad_state;
978 
979     gfx::Transform transform =
980         quad->shared_quad_state->quad_to_target_transform;
981 
982     // TODO(yiyix): Find a rect interior to each transformed quad.
983     if (last_sqs != quad->shared_quad_state) {
984       if (last_sqs->opacity == 1 && last_sqs->are_contents_opaque &&
985           last_sqs->quad_to_target_transform.Preserves2dAxisAlignment()) {
986         gfx::Rect sqs_rect_in_target =
987             cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
988                 last_sqs->quad_to_target_transform,
989                 last_sqs->visible_quad_layer_rect);
990 
991         // If a rounded corner is being applied then the visible rect for the
992         // sqs is actually even smaller. Reduce the rect size to get a
993         // rounded corner adjusted occluding region.
994         if (!last_sqs->rounded_corner_bounds.IsEmpty()) {
995           sqs_rect_in_target.Intersect(gfx::ToEnclosedRect(
996               GetOccludingRectForRRectF(last_sqs->rounded_corner_bounds)));
997         }
998 
999         if (last_sqs->is_clipped)
1000           sqs_rect_in_target.Intersect(last_sqs->clip_rect);
1001 
1002         // If region complexity is above our threshold, remove the smallest
1003         // rects from occlusion region.
1004         occlusion_in_target_space.Union(sqs_rect_in_target);
1005         while (occlusion_in_target_space.GetRegionComplexity() >
1006                settings_.kMaximumOccluderComplexity) {
1007           gfx::Rect smallest_rect = *occlusion_in_target_space.begin();
1008           for (const auto& occluding_rect : occlusion_in_target_space) {
1009             if (occluding_rect.size().GetArea() <
1010                 smallest_rect.size().GetArea())
1011               smallest_rect = occluding_rect;
1012           }
1013           occlusion_in_target_space.Subtract(smallest_rect);
1014         }
1015       }
1016       // If the visible_rect of the current shared quad state does not
1017       // intersect with the occlusion rect, we can skip draw occlusion checks
1018       // for quads in the current SharedQuadState.
1019       last_sqs = quad->shared_quad_state;
1020       occlusion_in_quad_content_space.Clear();
1021       render_pass_quads_in_content_space = gfx::Rect();
1022       const auto current_sqs_in_target_space =
1023           cc::MathUtil::MapEnclosingClippedRect(
1024               transform, last_sqs->visible_quad_layer_rect);
1025       current_sqs_intersects_occlusion =
1026           occlusion_in_target_space.Intersects(current_sqs_in_target_space);
1027 
1028       // Compute the occlusion region in the quad content space for scale and
1029       // translation transforms. Note that 0 scale transform will fail the
1030       // positive scale check.
1031       if (current_sqs_intersects_occlusion &&
1032           transform.IsPositiveScaleOrTranslation()) {
1033         gfx::Transform reverse_transform;
1034         bool is_invertible = transform.GetInverse(&reverse_transform);
1035         // Scale transform can be inverted by multiplying 1/scale (given
1036         // scale > 0) and translation transform can be inverted by applying
1037         // the reversed directional translation. Therefore, |transform| is
1038         // always invertible.
1039         DCHECK(is_invertible);
1040         DCHECK_LE(occlusion_in_target_space.GetRegionComplexity(),
1041                   settings_.kMaximumOccluderComplexity);
1042 
1043         // Since transform can only be a scale or a translation matrix, it is
1044         // safe to use function MapEnclosedRectWith2dAxisAlignedTransform to
1045         // define occluded region in the quad content space with inverted
1046         // transform.
1047         for (const gfx::Rect& rect_in_target_space :
1048              occlusion_in_target_space) {
1049           if (current_sqs_in_target_space.Intersects(rect_in_target_space)) {
1050             auto rect_in_content =
1051                 cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
1052                     reverse_transform, rect_in_target_space);
1053             occlusion_in_quad_content_space.Union(
1054                 SafeConvertRectForRegion(rect_in_content));
1055           }
1056         }
1057 
1058         // A render pass quad may apply some filter or transform to an
1059         // underlying quad. Do not split quads when they intersect with a render
1060         // pass quad.
1061         if (current_sqs_in_target_space.Intersects(
1062                 backdrop_filters_in_target_space.bounds())) {
1063           for (const auto& rect_in_target_space :
1064                backdrop_filters_in_target_space) {
1065             auto rect_in_content =
1066                 cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
1067                     reverse_transform, rect_in_target_space);
1068             render_pass_quads_in_content_space.Union(rect_in_content);
1069           }
1070         }
1071       }
1072     }
1073 
1074     if (!current_sqs_intersects_occlusion) {
1075       ++quad;
1076       continue;
1077     }
1078 
1079     if (occlusion_in_quad_content_space.Contains(quad->visible_rect)) {
1080       // Case 1: for simple transforms (scale or translation), define the
1081       // occlusion region in the quad content space. If |quad| is not
1082       // shown on the screen, then set its rect and visible_rect to be empty.
1083       quad->visible_rect.set_size(gfx::Size());
1084     } else if (occlusion_in_quad_content_space.Intersects(quad->visible_rect)) {
1085       // Case 2: for simple transforms, if the quad is partially shown on
1086       // screen and the region formed by (occlusion region - visible_rect) is
1087       // a rect, then update visible_rect to the resulting rect.
1088       cc::Region visible_region = quad->visible_rect;
1089       visible_region.Subtract(occlusion_in_quad_content_space);
1090       quad->visible_rect = visible_region.bounds();
1091 
1092       // Split quad into multiple draw quads when area can be reduce by
1093       // more than X fragments.
1094       const bool should_split_quads =
1095           enable_quad_splitting_ &&
1096           !visible_region.Intersects(render_pass_quads_in_content_space) &&
1097           ReduceComplexity(visible_region, settings_.quad_split_limit,
1098                            &cached_visible_region_) &&
1099           CanSplitQuad(quad->material, ComputeArea(cached_visible_region_),
1100                        visible_region.bounds().size().GetArea(),
1101                        settings_.minimum_fragments_reduced,
1102                        device_scale_factor_);
1103       if (should_split_quads) {
1104         auto new_quad = pass->quad_list.InsertCopyBeforeDrawQuad(
1105             quad, cached_visible_region_.size() - 1);
1106         for (const auto& visible_rect : cached_visible_region_) {
1107           new_quad->visible_rect = visible_rect;
1108           ++new_quad;
1109         }
1110         quad = new_quad;
1111         continue;
1112       }
1113     } else if (occlusion_in_quad_content_space.IsEmpty() &&
1114                occlusion_in_target_space.Contains(
1115                    cc::MathUtil::MapEnclosingClippedRect(transform,
1116                                                          quad->visible_rect))) {
1117       // Case 3: for non simple transforms, define the occlusion region in
1118       // target space. If |quad| is not shown on the screen, then set its
1119       // rect and visible_rect to be empty.
1120       quad->visible_rect.set_size(gfx::Size());
1121     }
1122     ++quad;
1123   }
1124 }
1125 
SetPreferredFrameInterval(base::TimeDelta interval)1126 void Display::SetPreferredFrameInterval(base::TimeDelta interval) {
1127   client_->SetPreferredFrameInterval(interval);
1128 }
1129 
GetPreferredFrameIntervalForFrameSinkId(const FrameSinkId & id)1130 base::TimeDelta Display::GetPreferredFrameIntervalForFrameSinkId(
1131     const FrameSinkId& id) {
1132   return client_->GetPreferredFrameIntervalForFrameSinkId(id);
1133 }
1134 
SetSupportedFrameIntervals(std::vector<base::TimeDelta> intervals)1135 void Display::SetSupportedFrameIntervals(
1136     std::vector<base::TimeDelta> intervals) {
1137   frame_rate_decider_->SetSupportedFrameIntervals(std::move(intervals));
1138 }
1139 
GetCacheBackBufferCb()1140 base::ScopedClosureRunner Display::GetCacheBackBufferCb() {
1141   return output_surface_->GetCacheBackBufferCb();
1142 }
1143 
1144 }  // namespace viz
1145