1 // Copyright 2012 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/direct_renderer.h"
6 
7 #include <limits.h>
8 #include <stddef.h>
9 
10 #include <utility>
11 #include <vector>
12 
13 #include "base/auto_reset.h"
14 #include "base/containers/circular_deque.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/numerics/safe_conversions.h"
18 #include "base/stl_util.h"
19 #include "base/trace_event/trace_event.h"
20 #include "build/build_config.h"
21 #include "cc/base/math_util.h"
22 #include "cc/paint/filter_operations.h"
23 #include "components/viz/common/display/renderer_settings.h"
24 #include "components/viz/common/frame_sinks/copy_output_request.h"
25 #include "components/viz/common/frame_sinks/copy_output_util.h"
26 #include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
27 #include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
28 #include "components/viz/common/quads/draw_quad.h"
29 #include "components/viz/service/display/bsp_tree.h"
30 #include "components/viz/service/display/bsp_walk_action.h"
31 #include "components/viz/service/display/output_surface.h"
32 #include "components/viz/service/display/skia_output_surface.h"
33 #include "ui/gfx/geometry/quad_f.h"
34 #include "ui/gfx/geometry/rect_conversions.h"
35 #include "ui/gfx/transform.h"
36 #include "ui/gfx/transform_util.h"
37 
38 namespace {
39 
40 // Returns the bounding box that contains the specified rounded corner.
ComputeRoundedCornerBoundingBox(const gfx::RRectF & rrect,const gfx::RRectF::Corner corner)41 gfx::RectF ComputeRoundedCornerBoundingBox(const gfx::RRectF& rrect,
42                                            const gfx::RRectF::Corner corner) {
43   auto radii = rrect.GetCornerRadii(corner);
44   gfx::RectF bounding_box(radii.x(), radii.y());
45   switch (corner) {
46     case gfx::RRectF::Corner::kUpperLeft:
47       bounding_box.Offset(rrect.rect().x(), rrect.rect().y());
48       break;
49     case gfx::RRectF::Corner::kUpperRight:
50       bounding_box.Offset(rrect.rect().right() - radii.x(), rrect.rect().y());
51       break;
52     case gfx::RRectF::Corner::kLowerRight:
53       bounding_box.Offset(rrect.rect().right() - radii.x(),
54                           rrect.rect().bottom() - radii.y());
55       break;
56     case gfx::RRectF::Corner::kLowerLeft:
57       bounding_box.Offset(rrect.rect().x(), rrect.rect().bottom() - radii.y());
58       break;
59   }
60   return bounding_box;
61 }
62 
63 }  // namespace
64 
65 namespace viz {
66 
67 DirectRenderer::DrawingFrame::DrawingFrame() = default;
68 DirectRenderer::DrawingFrame::~DrawingFrame() = default;
69 
70 DirectRenderer::SwapFrameData::SwapFrameData() = default;
71 DirectRenderer::SwapFrameData::~SwapFrameData() = default;
72 DirectRenderer::SwapFrameData::SwapFrameData(SwapFrameData&&) = default;
73 DirectRenderer::SwapFrameData& DirectRenderer::SwapFrameData::operator=(
74     SwapFrameData&&) = default;
75 
DirectRenderer(const RendererSettings * settings,const DebugRendererSettings * debug_settings,OutputSurface * output_surface,DisplayResourceProvider * resource_provider,OverlayProcessorInterface * overlay_processor)76 DirectRenderer::DirectRenderer(const RendererSettings* settings,
77                                const DebugRendererSettings* debug_settings,
78                                OutputSurface* output_surface,
79                                DisplayResourceProvider* resource_provider,
80                                OverlayProcessorInterface* overlay_processor)
81     : settings_(settings),
82       debug_settings_(debug_settings),
83       output_surface_(output_surface),
84       resource_provider_(resource_provider),
85       overlay_processor_(overlay_processor) {
86   DCHECK(output_surface_);
87 }
88 
89 DirectRenderer::~DirectRenderer() = default;
90 
Initialize()91 void DirectRenderer::Initialize() {
92   auto* context_provider = output_surface_->context_provider();
93 
94   use_partial_swap_ = settings_->partial_swap_enabled && CanPartialSwap();
95   allow_empty_swap_ = use_partial_swap_;
96   if (context_provider) {
97     if (context_provider->ContextCapabilities().commit_overlay_planes)
98       allow_empty_swap_ = true;
99 #if DCHECK_IS_ON()
100     supports_occlusion_query_ =
101         context_provider->ContextCapabilities().occlusion_query;
102 #endif
103   } else {
104     allow_empty_swap_ |=
105         output_surface_->capabilities().supports_commit_overlay_planes;
106   }
107 
108   initialized_ = true;
109 }
110 
111 // static
QuadVertexRect()112 gfx::RectF DirectRenderer::QuadVertexRect() {
113   return gfx::RectF(-0.5f, -0.5f, 1.f, 1.f);
114 }
115 
116 // static
QuadRectTransform(gfx::Transform * quad_rect_transform,const gfx::Transform & quad_transform,const gfx::RectF & quad_rect)117 void DirectRenderer::QuadRectTransform(gfx::Transform* quad_rect_transform,
118                                        const gfx::Transform& quad_transform,
119                                        const gfx::RectF& quad_rect) {
120   *quad_rect_transform = quad_transform;
121   quad_rect_transform->Translate(0.5 * quad_rect.width() + quad_rect.x(),
122                                  0.5 * quad_rect.height() + quad_rect.y());
123   quad_rect_transform->Scale(quad_rect.width(), quad_rect.height());
124 }
125 
InitializeViewport(DrawingFrame * frame,const gfx::Rect & draw_rect,const gfx::Rect & viewport_rect,const gfx::Size & surface_size)126 void DirectRenderer::InitializeViewport(DrawingFrame* frame,
127                                         const gfx::Rect& draw_rect,
128                                         const gfx::Rect& viewport_rect,
129                                         const gfx::Size& surface_size) {
130   DCHECK_GE(viewport_rect.x(), 0);
131   DCHECK_GE(viewport_rect.y(), 0);
132   DCHECK_LE(viewport_rect.right(), surface_size.width());
133   DCHECK_LE(viewport_rect.bottom(), surface_size.height());
134   bool flip_y = FlippedFramebuffer();
135   if (flip_y) {
136     frame->projection_matrix = gfx::OrthoProjectionMatrix(
137         draw_rect.x(), draw_rect.right(), draw_rect.bottom(), draw_rect.y());
138   } else {
139     frame->projection_matrix = gfx::OrthoProjectionMatrix(
140         draw_rect.x(), draw_rect.right(), draw_rect.y(), draw_rect.bottom());
141   }
142 
143   gfx::Rect window_rect = viewport_rect;
144   if (flip_y)
145     window_rect.set_y(surface_size.height() - viewport_rect.bottom());
146   frame->window_matrix =
147       gfx::WindowMatrix(window_rect.x(), window_rect.y(), window_rect.width(),
148                         window_rect.height());
149   current_draw_rect_ = draw_rect;
150   current_viewport_rect_ = viewport_rect;
151   current_surface_size_ = surface_size;
152   current_window_space_viewport_ = window_rect;
153 }
154 
MoveFromDrawToWindowSpace(const gfx::Rect & draw_rect) const155 gfx::Rect DirectRenderer::MoveFromDrawToWindowSpace(
156     const gfx::Rect& draw_rect) const {
157   gfx::Rect window_rect = draw_rect;
158   window_rect -= current_draw_rect_.OffsetFromOrigin();
159   window_rect += current_viewport_rect_.OffsetFromOrigin();
160   if (FlippedFramebuffer())
161     window_rect.set_y(current_surface_size_.height() - window_rect.bottom());
162   return window_rect;
163 }
164 
CanPassBeDrawnDirectly(const AggregatedRenderPass * pass)165 const DrawQuad* DirectRenderer::CanPassBeDrawnDirectly(
166     const AggregatedRenderPass* pass) {
167   return nullptr;
168 }
169 
SetVisible(bool visible)170 void DirectRenderer::SetVisible(bool visible) {
171   DCHECK(initialized_);
172   if (visible_ == visible)
173     return;
174   visible_ = visible;
175   DidChangeVisibility();
176 }
177 
DecideRenderPassAllocationsForFrame(const AggregatedRenderPassList & render_passes_in_draw_order)178 void DirectRenderer::DecideRenderPassAllocationsForFrame(
179     const AggregatedRenderPassList& render_passes_in_draw_order) {
180   DCHECK(render_pass_bypass_quads_.empty());
181 
182   auto& root_render_pass = render_passes_in_draw_order.back();
183 
184   base::flat_map<AggregatedRenderPassId, RenderPassRequirements>
185       render_passes_in_frame;
186   for (const auto& pass : render_passes_in_draw_order) {
187     // If there's a copy request, we need an explicit renderpass backing so
188     // only try to draw directly if there are no copy requests.
189     if (pass != root_render_pass && pass->copy_requests.empty()) {
190       if (const DrawQuad* quad = CanPassBeDrawnDirectly(pass.get())) {
191         // If the render pass is drawn directly, it will not be drawn from as
192         // a render pass so it's not added to the map.
193         render_pass_bypass_quads_[pass->id] = quad;
194         continue;
195       }
196     }
197     render_passes_in_frame[pass->id] = {
198         CalculateTextureSizeForRenderPass(pass.get()), pass->generate_mipmap};
199   }
200   UMA_HISTOGRAM_COUNTS_1000(
201       "Compositing.Display.FlattenedRenderPassCount",
202       base::saturated_cast<int>(render_passes_in_draw_order.size() -
203                                 render_pass_bypass_quads_.size()));
204   UpdateRenderPassTextures(render_passes_in_draw_order, render_passes_in_frame);
205 }
206 
DrawFrame(AggregatedRenderPassList * render_passes_in_draw_order,float device_scale_factor,const gfx::Size & device_viewport_size,const gfx::DisplayColorSpaces & display_color_spaces,SurfaceDamageRectList * surface_damage_rect_list)207 void DirectRenderer::DrawFrame(
208     AggregatedRenderPassList* render_passes_in_draw_order,
209     float device_scale_factor,
210     const gfx::Size& device_viewport_size,
211     const gfx::DisplayColorSpaces& display_color_spaces,
212     SurfaceDamageRectList* surface_damage_rect_list) {
213   DCHECK(visible_);
214   TRACE_EVENT0("viz,benchmark", "DirectRenderer::DrawFrame");
215   UMA_HISTOGRAM_COUNTS_1M(
216       "Renderer4.renderPassCount",
217       base::saturated_cast<int>(render_passes_in_draw_order->size()));
218 
219   auto* root_render_pass = render_passes_in_draw_order->back().get();
220   DCHECK(root_render_pass);
221 
222 #if DCHECK_IS_ON()
223   bool overdraw_tracing_enabled;
224   TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"),
225                                      &overdraw_tracing_enabled);
226   DLOG_IF(WARNING, !overdraw_tracing_support_missing_logged_once_ &&
227                        overdraw_tracing_enabled && !supports_occlusion_query_)
228       << "Overdraw tracing enabled on platform without support.";
229   overdraw_tracing_support_missing_logged_once_ = true;
230 #endif
231 
232   bool overdraw_feedback = debug_settings_->show_overdraw_feedback;
233   if (overdraw_feedback && !output_surface_->capabilities().supports_stencil) {
234 #if DCHECK_IS_ON()
235     DLOG_IF(WARNING, !overdraw_feedback_support_missing_logged_once_)
236         << "Overdraw feedback enabled on platform without support.";
237     overdraw_feedback_support_missing_logged_once_ = true;
238 #endif
239     overdraw_feedback = false;
240   }
241   base::AutoReset<bool> auto_reset_overdraw_feedback(&overdraw_feedback_,
242                                                      overdraw_feedback);
243 
244   current_frame_valid_ = true;
245   current_frame_ = DrawingFrame();
246   current_frame()->render_passes_in_draw_order = render_passes_in_draw_order;
247   current_frame()->root_render_pass = root_render_pass;
248   current_frame()->root_damage_rect = root_render_pass->damage_rect;
249   if (overlay_processor_) {
250     current_frame()->root_damage_rect.Union(
251         overlay_processor_->GetAndResetOverlayDamage());
252   }
253   if (DelegatedInkPointRendererBase* ink_renderer =
254           GetDelegatedInkPointRenderer()) {
255     // The path must be finalized before GetDamageRect() can return an accurate
256     // rect that will allow the old trail to be removed and the new trail to
257     // be drawn at the same time.
258     ink_renderer->FinalizePathForDraw();
259     gfx::Rect delegated_ink_damage_rect = ink_renderer->GetDamageRect();
260 
261     // The viewport could have changed size since the presentation area was
262     // created and propagated, such as if is window was resized. Intersect the
263     // viewport here to ensure the damage rect doesn't extend beyond the current
264     // viewport.
265     delegated_ink_damage_rect.Intersect(gfx::Rect(device_viewport_size));
266     current_frame()->root_damage_rect.Union(delegated_ink_damage_rect);
267   }
268   current_frame()->root_damage_rect.Intersect(gfx::Rect(device_viewport_size));
269   current_frame()->device_viewport_size = device_viewport_size;
270   current_frame()->display_color_spaces = display_color_spaces;
271 
272   output_surface_->SetNeedsMeasureNextDrawLatency();
273   BeginDrawingFrame();
274 
275   // RenderPass owns filters, backdrop_filters, etc., and will outlive this
276   // function call. So it is safe to store pointers in these maps.
277   for (const auto& pass : *render_passes_in_draw_order) {
278     if (!pass->filters.IsEmpty())
279       render_pass_filters_[pass->id] = &pass->filters;
280     if (!pass->backdrop_filters.IsEmpty()) {
281       render_pass_backdrop_filters_[pass->id] = &pass->backdrop_filters;
282       render_pass_backdrop_filter_bounds_[pass->id] =
283           pass->backdrop_filter_bounds;
284       if (pass->backdrop_filters.HasFilterThatMovesPixels()) {
285         backdrop_filter_output_rects_[pass->id] =
286             cc::MathUtil::MapEnclosingClippedRect(
287                 pass->transform_to_root_target, pass->output_rect);
288       }
289     }
290   }
291 
292   bool frame_has_alpha =
293       current_frame()->root_render_pass->has_transparent_background;
294   gfx::ColorSpace frame_color_space = RootRenderPassColorSpace();
295   gfx::BufferFormat frame_buffer_format =
296       current_frame()->display_color_spaces.GetOutputBufferFormat(
297           current_frame()->root_render_pass->content_color_usage,
298           frame_has_alpha);
299   if (overlay_processor_) {
300     // Display transform and viewport size are needed for overlay validator on
301     // Android SurfaceControl, and viewport size is need on Windows. These need
302     // to be called before ProcessForOverlays.
303     overlay_processor_->SetDisplayTransformHint(
304         output_surface_->GetDisplayTransform());
305     overlay_processor_->SetViewportSize(device_viewport_size);
306 
307     // Before ProcessForOverlay calls into the hardware to ask about whether the
308     // overlay setup can be handled, we need to set up the primary plane.
309     OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane =
310         nullptr;
311     if (output_surface_->IsDisplayedAsOverlayPlane()) {
312       // OutputSurface::GetOverlayMailbox() returns the mailbox for the last
313       // used buffer, which is most likely different from the one being used
314       // this frame. However, for the purpose of testing the overlay
315       // configuration, the mailbox for ANY buffer from BufferQueue is good
316       // enough because they're all created with identical properties.
317       current_frame()->output_surface_plane =
318           overlay_processor_->ProcessOutputSurfaceAsOverlay(
319               device_viewport_size, frame_buffer_format, frame_color_space,
320               frame_has_alpha, output_surface_->GetOverlayMailbox());
321       primary_plane = &(current_frame()->output_surface_plane.value());
322     }
323 
324     // Attempt to replace some or all of the quads of the root render pass with
325     // overlays.
326     overlay_processor_->ProcessForOverlays(
327         resource_provider_, render_passes_in_draw_order,
328         output_surface_->color_matrix(), render_pass_filters_,
329         render_pass_backdrop_filters_, surface_damage_rect_list, primary_plane,
330         &current_frame()->overlay_list, &current_frame()->root_damage_rect,
331         &current_frame()->root_content_bounds);
332 
333     // If we promote any quad to an underlay then the main plane must support
334     // alpha.
335     // TODO(ccameron): We should update |frame_color_space|, and
336     // |frame_buffer_format| based on the change in |frame_has_alpha|.
337     if (current_frame()->output_surface_plane) {
338       frame_has_alpha |= current_frame()->output_surface_plane->enable_blending;
339       root_render_pass->has_transparent_background = frame_has_alpha;
340     }
341 
342     overlay_processor_->AdjustOutputSurfaceOverlay(
343         &(current_frame()->output_surface_plane));
344   }
345 
346   // Only reshape when we know we are going to draw. Otherwise, the reshape
347   // can leave the window at the wrong size if we never draw and the proper
348   // viewport size is never set.
349   bool use_stencil = overdraw_feedback_;
350   bool needs_full_frame_redraw = false;
351   if (device_viewport_size != reshape_surface_size_ ||
352       device_scale_factor != reshape_device_scale_factor_ ||
353       frame_color_space != reshape_color_space_ ||
354       frame_buffer_format != reshape_buffer_format_ ||
355       use_stencil != reshape_use_stencil_) {
356     reshape_surface_size_ = device_viewport_size;
357     reshape_device_scale_factor_ = device_scale_factor;
358     reshape_color_space_ = frame_color_space;
359     reshape_buffer_format_ = frame_buffer_format;
360     reshape_use_stencil_ = overdraw_feedback_;
361     output_surface_->Reshape(reshape_surface_size_,
362                              reshape_device_scale_factor_, reshape_color_space_,
363                              *reshape_buffer_format_, reshape_use_stencil_);
364 #if defined(OS_APPLE)
365     // For Mac, all render passes will be promoted to CALayer, the redraw full
366     // frame is for the main surface only.
367     // TODO(penghuang): verify this logic with SkiaRenderer.
368     if (!output_surface_->capabilities().supports_surfaceless)
369       needs_full_frame_redraw = true;
370 #else
371     // The entire surface has to be redrawn if reshape is requested.
372     needs_full_frame_redraw = true;
373 #endif
374   }
375 
376   // Draw all non-root render passes except for the root render pass.
377   for (const auto& pass : *render_passes_in_draw_order) {
378     if (pass.get() == root_render_pass)
379       break;
380     DrawRenderPassAndExecuteCopyRequests(pass.get());
381   }
382 
383   bool skip_drawing_root_render_pass =
384       current_frame()->root_damage_rect.IsEmpty() && allow_empty_swap_ &&
385       !needs_full_frame_redraw;
386 
387   // If partial swap is not used, and the frame can not be skipped, the whole
388   // frame has to be redrawn.
389   if (!use_partial_swap_ && !skip_drawing_root_render_pass)
390     needs_full_frame_redraw = true;
391 
392   // If we need to redraw the frame, the whole output should be considered
393   // damaged.
394   if (needs_full_frame_redraw)
395     current_frame()->root_damage_rect = gfx::Rect(device_viewport_size);
396 
397   if (!skip_drawing_root_render_pass)
398     DrawRenderPassAndExecuteCopyRequests(root_render_pass);
399 
400   // Use a fence to synchronize display of the main fb used by the output
401   // surface. Note that gpu_fence_id may have the special value 0 ("no fence")
402   // if fences are not supported. In that case synchronization will happen
403   // through other means on the service side.
404   // TODO(afrantzis): Consider using per-overlay fences instead of the one
405   // associated with the output surface when possible.
406   if (current_frame()->output_surface_plane)
407     current_frame()->output_surface_plane->gpu_fence_id =
408         output_surface_->UpdateGpuFence();
409 
410   if (overlay_processor_)
411     overlay_processor_->TakeOverlayCandidates(&current_frame()->overlay_list);
412 
413   FinishDrawingFrame();
414 
415   if (overlay_processor_)
416     overlay_processor_->ScheduleOverlays(resource_provider_);
417 
418   render_passes_in_draw_order->clear();
419   render_pass_filters_.clear();
420   render_pass_backdrop_filters_.clear();
421   render_pass_backdrop_filter_bounds_.clear();
422   render_pass_bypass_quads_.clear();
423   backdrop_filter_output_rects_.clear();
424 
425   current_frame_valid_ = false;
426 }
427 
GetTargetDamageBoundingRect() const428 gfx::Rect DirectRenderer::GetTargetDamageBoundingRect() const {
429   gfx::Rect bounding_rect = output_surface_->GetCurrentFramebufferDamage();
430   if (overlay_processor_) {
431     bounding_rect.Union(
432         overlay_processor_->GetPreviousFrameOverlaysBoundingRect());
433   }
434   return bounding_rect;
435 }
436 
DeviceViewportRectInDrawSpace() const437 gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace() const {
438   gfx::Rect device_viewport_rect(current_frame()->device_viewport_size);
439   device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
440   device_viewport_rect += current_draw_rect_.OffsetFromOrigin();
441   return device_viewport_rect;
442 }
443 
OutputSurfaceRectInDrawSpace() const444 gfx::Rect DirectRenderer::OutputSurfaceRectInDrawSpace() const {
445   if (current_frame()->current_render_pass ==
446       current_frame()->root_render_pass) {
447     gfx::Rect output_surface_rect(current_frame()->device_viewport_size);
448     output_surface_rect -= current_viewport_rect_.OffsetFromOrigin();
449     output_surface_rect += current_draw_rect_.OffsetFromOrigin();
450     return output_surface_rect;
451   } else {
452     return current_frame()->current_render_pass->output_rect;
453   }
454 }
455 
ShouldSkipQuad(const DrawQuad & quad,const gfx::Rect & render_pass_scissor)456 bool DirectRenderer::ShouldSkipQuad(const DrawQuad& quad,
457                                     const gfx::Rect& render_pass_scissor) {
458   if (render_pass_scissor.IsEmpty())
459     return true;
460 
461   gfx::Rect target_rect = cc::MathUtil::MapEnclosingClippedRect(
462       quad.shared_quad_state->quad_to_target_transform, quad.visible_rect);
463   if (quad.shared_quad_state->is_clipped)
464     target_rect.Intersect(quad.shared_quad_state->clip_rect);
465 
466   target_rect.Intersect(render_pass_scissor);
467   return target_rect.IsEmpty();
468 }
469 
SetScissorStateForQuad(const DrawQuad & quad,const gfx::Rect & render_pass_scissor,bool use_render_pass_scissor)470 void DirectRenderer::SetScissorStateForQuad(
471     const DrawQuad& quad,
472     const gfx::Rect& render_pass_scissor,
473     bool use_render_pass_scissor) {
474   if (use_render_pass_scissor) {
475     gfx::Rect quad_scissor_rect = render_pass_scissor;
476     if (quad.shared_quad_state->is_clipped)
477       quad_scissor_rect.Intersect(quad.shared_quad_state->clip_rect);
478     SetScissorTestRectInDrawSpace(quad_scissor_rect);
479     return;
480   } else if (quad.shared_quad_state->is_clipped) {
481     SetScissorTestRectInDrawSpace(quad.shared_quad_state->clip_rect);
482     return;
483   }
484 
485   EnsureScissorTestDisabled();
486 }
487 
SetScissorTestRectInDrawSpace(const gfx::Rect & draw_space_rect)488 void DirectRenderer::SetScissorTestRectInDrawSpace(
489     const gfx::Rect& draw_space_rect) {
490   gfx::Rect window_space_rect = MoveFromDrawToWindowSpace(draw_space_rect);
491   SetScissorTestRect(window_space_rect);
492 }
493 
DoDrawPolygon(const DrawPolygon & poly,const gfx::Rect & render_pass_scissor,bool use_render_pass_scissor)494 void DirectRenderer::DoDrawPolygon(const DrawPolygon& poly,
495                                    const gfx::Rect& render_pass_scissor,
496                                    bool use_render_pass_scissor) {
497   SetScissorStateForQuad(*poly.original_ref(), render_pass_scissor,
498                          use_render_pass_scissor);
499 
500   // If the poly has not been split, then it is just a normal DrawQuad,
501   // and we should save any extra processing that would have to be done.
502   if (!poly.is_split()) {
503     DoDrawQuad(poly.original_ref(), nullptr);
504     return;
505   }
506 
507   std::vector<gfx::QuadF> quads;
508   poly.ToQuads2D(&quads);
509   for (size_t i = 0; i < quads.size(); ++i) {
510     DoDrawQuad(poly.original_ref(), &quads[i]);
511   }
512 }
513 
FiltersForPass(AggregatedRenderPassId render_pass_id) const514 const cc::FilterOperations* DirectRenderer::FiltersForPass(
515     AggregatedRenderPassId render_pass_id) const {
516   auto it = render_pass_filters_.find(render_pass_id);
517   return it == render_pass_filters_.end() ? nullptr : it->second;
518 }
519 
BackdropFiltersForPass(AggregatedRenderPassId render_pass_id) const520 const cc::FilterOperations* DirectRenderer::BackdropFiltersForPass(
521     AggregatedRenderPassId render_pass_id) const {
522   auto it = render_pass_backdrop_filters_.find(render_pass_id);
523   return it == render_pass_backdrop_filters_.end() ? nullptr : it->second;
524 }
525 
BackdropFilterBoundsForPass(AggregatedRenderPassId render_pass_id) const526 const base::Optional<gfx::RRectF> DirectRenderer::BackdropFilterBoundsForPass(
527     AggregatedRenderPassId render_pass_id) const {
528   auto it = render_pass_backdrop_filter_bounds_.find(render_pass_id);
529   return it == render_pass_backdrop_filter_bounds_.end()
530              ? base::Optional<gfx::RRectF>()
531              : it->second;
532 }
533 
FlushPolygons(base::circular_deque<std::unique_ptr<DrawPolygon>> * poly_list,const gfx::Rect & render_pass_scissor,bool use_render_pass_scissor)534 void DirectRenderer::FlushPolygons(
535     base::circular_deque<std::unique_ptr<DrawPolygon>>* poly_list,
536     const gfx::Rect& render_pass_scissor,
537     bool use_render_pass_scissor) {
538   if (poly_list->empty()) {
539     return;
540   }
541 
542   BspTree bsp_tree(poly_list);
543   BspWalkActionDrawPolygon action_handler(this, render_pass_scissor,
544                                           use_render_pass_scissor);
545   bsp_tree.TraverseWithActionHandler(&action_handler);
546   DCHECK(poly_list->empty());
547 }
548 
DrawRenderPassAndExecuteCopyRequests(AggregatedRenderPass * render_pass)549 void DirectRenderer::DrawRenderPassAndExecuteCopyRequests(
550     AggregatedRenderPass* render_pass) {
551   if (render_pass_bypass_quads_.find(render_pass->id) !=
552       render_pass_bypass_quads_.end()) {
553     return;
554   }
555 
556   // Repeated draw to simulate a slower device for the evaluation of performance
557   // improvements in UI effects.
558   for (int i = 0; i < settings_->slow_down_compositing_scale_factor; ++i)
559     DrawRenderPass(render_pass);
560 
561   for (auto& request : render_pass->copy_requests) {
562     // Finalize the source subrect (output_rect, result_bounds,
563     // sampling_bounds), as the entirety of the RenderPass's output optionally
564     // clamped to the requested copy area. Then, compute the result rect
565     // (result_selection), which is the selection clamped to the maximum
566     // possible result bounds. If there will be zero pixels of output or the
567     // scaling ratio was not reasonable, do not proceed.
568     gfx::Rect output_rect = render_pass->output_rect;
569     if (request->has_area())
570       output_rect.Intersect(request->area());
571 
572     copy_output::RenderPassGeometry geometry;
573     geometry.result_bounds =
574         request->is_scaled() ? copy_output::ComputeResultRect(
575                                    gfx::Rect(output_rect.size()),
576                                    request->scale_from(), request->scale_to())
577                              : gfx::Rect(output_rect.size());
578 
579     geometry.result_selection = geometry.result_bounds;
580     if (request->has_result_selection())
581       geometry.result_selection.Intersect(request->result_selection());
582     if (geometry.result_selection.IsEmpty())
583       continue;
584 
585     geometry.sampling_bounds = MoveFromDrawToWindowSpace(output_rect);
586 
587     geometry.readback_offset =
588         MoveFromDrawToWindowSpace(geometry.result_selection +
589                                   output_rect.OffsetFromOrigin())
590             .OffsetFromOrigin();
591     CopyDrawnRenderPass(geometry, std::move(request));
592   }
593 }
594 
DrawRenderPass(const AggregatedRenderPass * render_pass)595 void DirectRenderer::DrawRenderPass(const AggregatedRenderPass* render_pass) {
596   TRACE_EVENT0("viz", "DirectRenderer::DrawRenderPass");
597   if (CanSkipRenderPass(render_pass))
598     return;
599   UseRenderPass(render_pass);
600 
601   // TODO(crbug.com/582554): This change applies only when Vulkan is enabled and
602   // it will be removed once SkiaRenderer has complete support for Vulkan.
603   if (current_frame()->current_render_pass !=
604           current_frame()->root_render_pass &&
605       !IsRenderPassResourceAllocated(render_pass->id))
606     return;
607 
608   const gfx::Rect surface_rect_in_draw_space = OutputSurfaceRectInDrawSpace();
609   gfx::Rect render_pass_scissor_in_draw_space = surface_rect_in_draw_space;
610 
611   bool is_root_render_pass =
612       current_frame()->current_render_pass == current_frame()->root_render_pass;
613   if (is_root_render_pass) {
614     render_pass_scissor_in_draw_space.Intersect(
615         DeviceViewportRectInDrawSpace());
616   }
617 
618   if (use_partial_swap_) {
619     render_pass_scissor_in_draw_space.Intersect(
620         ComputeScissorRectForRenderPass(current_frame()->current_render_pass));
621   }
622 
623   const bool render_pass_is_clipped =
624       !render_pass_scissor_in_draw_space.Contains(surface_rect_in_draw_space);
625 
626   // The SetDrawRectangleCHROMIUM spec requires that the scissor bit is always
627   // set on the root framebuffer or else the rendering may modify something
628   // outside the damage rectangle, even if the damage rectangle is the size of
629   // the full backbuffer.
630   const bool supports_dc_layers =
631       output_surface_->capabilities().supports_dc_layers;
632   const bool render_pass_requires_scissor =
633       render_pass_is_clipped || (supports_dc_layers && is_root_render_pass);
634 
635   const bool has_external_stencil_test =
636       is_root_render_pass && output_surface_->HasExternalStencilTest();
637   const bool should_clear_surface =
638       !has_external_stencil_test &&
639       (!is_root_render_pass || settings_->should_clear_root_render_pass);
640 
641   // If |has_external_stencil_test| we can't discard or clear. Make sure we
642   // don't need to.
643   DCHECK(!has_external_stencil_test ||
644          !current_frame()->current_render_pass->has_transparent_background);
645 
646   SurfaceInitializationMode mode;
647   if (should_clear_surface && render_pass_requires_scissor) {
648     mode = SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR;
649   } else if (should_clear_surface) {
650     mode = SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR;
651   } else {
652     mode = SURFACE_INITIALIZATION_MODE_PRESERVE;
653   }
654 
655   PrepareSurfaceForPass(
656       mode, MoveFromDrawToWindowSpace(render_pass_scissor_in_draw_space));
657 
658   if (is_root_render_pass)
659     last_root_render_pass_scissor_rect_ = render_pass_scissor_in_draw_space;
660 
661   const QuadList& quad_list = render_pass->quad_list;
662   base::circular_deque<std::unique_ptr<DrawPolygon>> poly_list;
663 
664   int next_polygon_id = 0;
665   int last_sorting_context_id = 0;
666   for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
667        ++it) {
668     const DrawQuad& quad = **it;
669 
670     if (render_pass_is_clipped &&
671         ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) {
672       continue;
673     }
674 
675     if (last_sorting_context_id != quad.shared_quad_state->sorting_context_id) {
676       last_sorting_context_id = quad.shared_quad_state->sorting_context_id;
677       FlushPolygons(&poly_list, render_pass_scissor_in_draw_space,
678                     render_pass_requires_scissor);
679     }
680 
681     // This layer is in a 3D sorting context so we add it to the list of
682     // polygons to go into the BSP tree.
683     if (quad.shared_quad_state->sorting_context_id != 0) {
684       // TODO(danakj): It's sad to do a malloc here to compare. Maybe construct
685       // this on the stack and move it into the list.
686       auto new_polygon = std::make_unique<DrawPolygon>(
687           *it, gfx::RectF(quad.visible_rect),
688           quad.shared_quad_state->quad_to_target_transform, next_polygon_id++);
689       if (new_polygon->points().size() > 2u) {
690         poly_list.push_back(std::move(new_polygon));
691       }
692       continue;
693     }
694 
695     // We are not in a 3d sorting context, so we should draw the quad normally.
696     SetScissorStateForQuad(quad, render_pass_scissor_in_draw_space,
697                            render_pass_requires_scissor);
698 
699     DoDrawQuad(&quad, nullptr);
700   }
701   FlushPolygons(&poly_list, render_pass_scissor_in_draw_space,
702                 render_pass_requires_scissor);
703   FinishDrawingQuadList();
704 
705   if (is_root_render_pass && overdraw_feedback_)
706     FlushOverdrawFeedback(render_pass_scissor_in_draw_space);
707 
708   if (render_pass->generate_mipmap)
709     GenerateMipmap();
710 }
711 
CanSkipRenderPass(const AggregatedRenderPass * render_pass) const712 bool DirectRenderer::CanSkipRenderPass(
713     const AggregatedRenderPass* render_pass) const {
714   if (render_pass == current_frame()->root_render_pass)
715     return false;
716 
717   // TODO(crbug.com/783275): It's possible to skip a child RenderPass if damage
718   // does not overlap it, since that means nothing has changed:
719   //   ComputeScissorRectForRenderPass(render_pass).IsEmpty()
720   // However that caused crashes where the RenderPass' texture was not present
721   // (never seen the RenderPass before, or the texture was deleted when not used
722   // for a frame). It could avoid skipping if there is no texture present, which
723   // is what was done for a while, but this seems to papering over a missing
724   // damage problem, or we're failing to understand the system wholey.
725   // If attempted again this should probably CHECK() that the texture exists,
726   // and attempt to figure out where the new RenderPass texture without damage
727   // is coming from.
728 
729   // If the RenderPass wants to be cached, then we only draw it if we need to.
730   // When damage is present, then we can't skip the RenderPass. Or if the
731   // texture does not exist (first frame, or was deleted) then we can't skip
732   // the RenderPass.
733   if (render_pass->cache_render_pass) {
734     if (render_pass->has_damage_from_contributing_content)
735       return false;
736     return IsRenderPassResourceAllocated(render_pass->id);
737   }
738 
739   return false;
740 }
741 
UseRenderPass(const AggregatedRenderPass * render_pass)742 void DirectRenderer::UseRenderPass(const AggregatedRenderPass* render_pass) {
743   current_frame()->current_render_pass = render_pass;
744   if (render_pass == current_frame()->root_render_pass) {
745     BindFramebufferToOutputSurface();
746     if (output_surface_->capabilities().supports_dc_layers)
747       output_surface_->SetDrawRectangle(current_frame()->root_damage_rect);
748     InitializeViewport(current_frame(), render_pass->output_rect,
749                        gfx::Rect(current_frame()->device_viewport_size),
750                        current_frame()->device_viewport_size);
751     return;
752   }
753 
754   gfx::Size enlarged_size = CalculateTextureSizeForRenderPass(render_pass);
755   enlarged_size.Enlarge(enlarge_pass_texture_amount_.width(),
756                         enlarge_pass_texture_amount_.height());
757 
758   AllocateRenderPassResourceIfNeeded(
759       render_pass->id, {enlarged_size, render_pass->generate_mipmap});
760 
761   // TODO(crbug.com/582554): This change applies only when Vulkan is enabled and
762   // it will be removed once SkiaRenderer has complete support for Vulkan.
763   if (!IsRenderPassResourceAllocated(render_pass->id))
764     return;
765 
766   BindFramebufferToTexture(render_pass->id);
767   InitializeViewport(current_frame(), render_pass->output_rect,
768                      gfx::Rect(render_pass->output_rect.size()),
769                      // If the render pass backing is cached, we might have
770                      // bigger size comparing to the size that was generated.
771                      GetRenderPassBackingPixelSize(render_pass->id));
772 }
773 
ComputeScissorRectForRenderPass(const AggregatedRenderPass * render_pass) const774 gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass(
775     const AggregatedRenderPass* render_pass) const {
776   const AggregatedRenderPass* root_render_pass =
777       current_frame()->root_render_pass;
778   gfx::Rect root_damage_rect = current_frame()->root_damage_rect;
779 
780   if (render_pass == root_render_pass) {
781     base::CheckedNumeric<int> display_area =
782         current_frame()->device_viewport_size.GetCheckedArea();
783     gfx::Rect frame_buffer_damage =
784         output_surface_->GetCurrentFramebufferDamage();
785     base::CheckedNumeric<int> root_damage_area =
786         root_damage_rect.size().GetCheckedArea();
787     if (display_area.IsValid() && root_damage_area.IsValid()) {
788       DCHECK_GT(static_cast<int>(display_area.ValueOrDie()), 0);
789       {
790         base::CheckedNumeric<int> frame_buffer_damage_area =
791             frame_buffer_damage.size().GetCheckedArea();
792         int ratio =
793             (frame_buffer_damage_area / display_area).ValueOrDefault(INT_MAX);
794         UMA_HISTOGRAM_PERCENTAGE(
795             "Compositing.DirectRenderer.PartialSwap.FrameBufferDamage",
796             100ull * ratio);
797       }
798       {
799         int ratio = (root_damage_area / display_area).ValueOrDie();
800         UMA_HISTOGRAM_PERCENTAGE(
801             "Compositing.DirectRenderer.PartialSwap.RootDamage",
802             100ull * ratio);
803       }
804 
805       root_damage_rect.Union(frame_buffer_damage);
806 
807       // If the root damage rect intersects any child render pass that has a
808       // pixel-moving backdrop-filter, expand the damage to include the entire
809       // child pass. See crbug.com/986206 for context.
810       if (!backdrop_filter_output_rects_.empty() &&
811           !root_damage_rect.IsEmpty()) {
812         for (auto* quad : render_pass->quad_list) {
813           // Sanity check: we should not have a Compositor
814           // CompositorRenderPassDrawQuad here.
815           DCHECK_NE(quad->material, DrawQuad::Material::kCompositorRenderPass);
816           if (quad->material == DrawQuad::Material::kAggregatedRenderPass) {
817             auto iter = backdrop_filter_output_rects_.find(
818                 AggregatedRenderPassDrawQuad::MaterialCast(quad)
819                     ->render_pass_id);
820             if (iter != backdrop_filter_output_rects_.end()) {
821               gfx::Rect this_output_rect = iter->second;
822               if (root_damage_rect.Intersects(this_output_rect))
823                 root_damage_rect.Union(this_output_rect);
824             }
825           }
826         }
827       }
828 
829       // Total damage after all adjustments.
830       base::CheckedNumeric<int> total_damage_area =
831           root_damage_rect.size().GetCheckedArea();
832       {
833         int ratio = (total_damage_area / display_area).ValueOrDefault(INT_MAX);
834         UMA_HISTOGRAM_PERCENTAGE(
835             "Compositing.DirectRenderer.PartialSwap.TotalDamage",
836             100ull * ratio);
837       }
838       {
839         int ratio = ((total_damage_area - root_damage_area) / display_area)
840                         .ValueOrDefault(INT_MAX);
841         UMA_HISTOGRAM_PERCENTAGE(
842             "Compositing.DirectRenderer.PartialSwap.ExtraDamage",
843             100ull * ratio);
844       }
845     }
846 
847     return root_damage_rect;
848   }
849 
850   // If the root damage rect has been expanded due to overlays, all the other
851   // damage rect calculations are incorrect.
852   if (!root_render_pass->damage_rect.Contains(root_damage_rect))
853     return render_pass->output_rect;
854 
855   DCHECK(render_pass->copy_requests.empty() ||
856          (render_pass->damage_rect == render_pass->output_rect));
857   return render_pass->damage_rect;
858 }
859 
CalculateTextureSizeForRenderPass(const AggregatedRenderPass * render_pass)860 gfx::Size DirectRenderer::CalculateTextureSizeForRenderPass(
861     const AggregatedRenderPass* render_pass) {
862   // Round the size of the render pass backings to a multiple of 64 pixels. This
863   // reduces memory fragmentation. https://crbug.com/146070. This also allows
864   // backings to be more easily reused during a resize operation.
865   int width = render_pass->output_rect.width();
866   int height = render_pass->output_rect.height();
867   if (!settings_->dont_round_texture_sizes_for_pixel_tests) {
868     int multiple = 64;
869     width = cc::MathUtil::CheckedRoundUp(width, multiple);
870     height = cc::MathUtil::CheckedRoundUp(height, multiple);
871   }
872   return gfx::Size(width, height);
873 }
874 
SetCurrentFrameForTesting(const DrawingFrame & frame)875 void DirectRenderer::SetCurrentFrameForTesting(const DrawingFrame& frame) {
876   current_frame_valid_ = true;
877   current_frame_ = frame;
878 }
879 
HasAllocatedResourcesForTesting(const AggregatedRenderPassId & render_pass_id) const880 bool DirectRenderer::HasAllocatedResourcesForTesting(
881     const AggregatedRenderPassId& render_pass_id) const {
882   return IsRenderPassResourceAllocated(render_pass_id);
883 }
884 
ShouldApplyRoundedCorner(const DrawQuad * quad) const885 bool DirectRenderer::ShouldApplyRoundedCorner(const DrawQuad* quad) const {
886   const SharedQuadState* sqs = quad->shared_quad_state;
887   const gfx::MaskFilterInfo& mask_filter_info = sqs->mask_filter_info;
888 
889   // There is no rounded corner set.
890   if (!mask_filter_info.HasRoundedCorners())
891     return false;
892 
893   const gfx::RRectF& rounded_corner_bounds =
894       mask_filter_info.rounded_corner_bounds();
895 
896   const gfx::RectF target_quad = cc::MathUtil::MapClippedRect(
897       sqs->quad_to_target_transform, gfx::RectF(quad->visible_rect));
898 
899   const gfx::RRectF::Corner corners[] = {
900       gfx::RRectF::Corner::kUpperLeft, gfx::RRectF::Corner::kUpperRight,
901       gfx::RRectF::Corner::kLowerRight, gfx::RRectF::Corner::kLowerLeft};
902   for (auto c : corners) {
903     if (ComputeRoundedCornerBoundingBox(rounded_corner_bounds, c)
904             .Intersects(target_quad)) {
905       return true;
906     }
907   }
908   return false;
909 }
910 
RootRenderPassColorSpace() const911 gfx::ColorSpace DirectRenderer::RootRenderPassColorSpace() const {
912   return current_frame()->display_color_spaces.GetOutputColorSpace(
913       current_frame()->root_render_pass->content_color_usage,
914       current_frame()->root_render_pass->has_transparent_background);
915 }
916 
CurrentRenderPassColorSpace() const917 gfx::ColorSpace DirectRenderer::CurrentRenderPassColorSpace() const {
918   if (current_frame()->current_render_pass ==
919       current_frame()->root_render_pass) {
920     return RootRenderPassColorSpace();
921   }
922   return current_frame()->display_color_spaces.GetCompositingColorSpace(
923       current_frame()->current_render_pass->has_transparent_background,
924       current_frame()->current_render_pass->content_color_usage);
925 }
926 
CreateDelegatedInkPointRenderer()927 bool DirectRenderer::CreateDelegatedInkPointRenderer() {
928   return false;
929 }
930 
GetDelegatedInkPointRenderer()931 DelegatedInkPointRendererBase* DirectRenderer::GetDelegatedInkPointRenderer() {
932   return nullptr;
933 }
934 
SetDelegatedInkMetadata(std::unique_ptr<DelegatedInkMetadata> metadata)935 void DirectRenderer::SetDelegatedInkMetadata(
936     std::unique_ptr<DelegatedInkMetadata> metadata) {
937   if (!GetDelegatedInkPointRenderer() && !CreateDelegatedInkPointRenderer())
938     return;
939 
940   GetDelegatedInkPointRenderer()->SetDelegatedInkMetadata(std::move(metadata));
941 }
942 
DrawDelegatedInkTrail()943 void DirectRenderer::DrawDelegatedInkTrail() {
944   NOTREACHED();
945 }
946 
CompositeTimeTracingEnabled()947 bool DirectRenderer::CompositeTimeTracingEnabled() {
948   return false;
949 }
950 
AddCompositeTimeTraces(base::TimeTicks ready_timestamp)951 void DirectRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {}
952 
GetDelegatedInkTrailDamageRect()953 gfx::Rect DirectRenderer::GetDelegatedInkTrailDamageRect() {
954   if (!GetDelegatedInkPointRenderer())
955     return gfx::Rect();
956 
957   return GetDelegatedInkPointRenderer()->GetDamageRect();
958 }
959 
960 }  // namespace viz
961