summaryrefslogtreecommitdiff
path: root/chromium/components/viz/service/display
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/viz/service/display')
-rw-r--r--chromium/components/viz/service/display/DEPS1
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h7
-rw-r--r--chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc3
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.cc1
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc106
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h5
-rw-r--r--chromium/components/viz/service/display/display.cc108
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc87
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h21
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc28
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc32
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h5
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.cc26
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_unittest.cc12
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc6
-rw-r--r--chromium/components/viz/service/display/output_surface.h12
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.h4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.cc1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.cc4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.cc7
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.h1
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc1
-rw-r--r--chromium/components/viz/service/display/program_binding.cc1
-rw-r--r--chromium/components/viz/service/display/program_binding.h2
-rw-r--r--chromium/components/viz/service/display/renderer_perftest.cc3
-rw-r--r--chromium/components/viz/service/display/shader.h1
-rw-r--r--chromium/components/viz/service/display/skia_readback_pixeltest.cc3
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc76
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc5
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc494
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h107
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc796
38 files changed, 1500 insertions, 487 deletions
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index e21abf9abcb..39b3ff37c99 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -62,5 +62,6 @@ specific_include_rules = {
"+gpu/GLES2",
"+media",
"+third_party/libyuv",
+ "+ui/gl/gl_implementation.h",
],
}
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index 2594167459e..5e9c2f27322 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/service/viz_service_export.h"
+#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -23,7 +24,7 @@ class RenderPassDrawQuad;
// Holds information that is frequently shared between consecutive
// CALayerOverlays.
class VIZ_SERVICE_EXPORT CALayerOverlaySharedState
- : public base::RefCounted<CALayerOverlaySharedState> {
+ : public base::RefCountedThreadSafe<CALayerOverlaySharedState> {
public:
CALayerOverlaySharedState() {}
// Layers in a non-zero sorting context exist in the same 3D space and should
@@ -40,7 +41,7 @@ class VIZ_SERVICE_EXPORT CALayerOverlaySharedState
SkMatrix44 transform = SkMatrix44(SkMatrix44::kIdentity_Constructor);
private:
- friend class base::RefCounted<CALayerOverlaySharedState>;
+ friend class base::RefCountedThreadSafe<CALayerOverlaySharedState>;
~CALayerOverlaySharedState() {}
};
@@ -57,6 +58,8 @@ class VIZ_SERVICE_EXPORT CALayerOverlay {
// Texture that corresponds to an IOSurface to set as the content of the
// CALayer. If this is 0 then the CALayer is a solid color.
unsigned contents_resource_id = 0;
+ // Mailbox from contents_resource_id. It is used by SkiaRenderer.
+ gpu::Mailbox mailbox;
// The contents rect property for the CALayer.
gfx::RectF contents_rect;
// The bounds for the CALayer in pixels.
diff --git a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
index dad254b2c68..c684f2d5498 100644
--- a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
+++ b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -169,6 +169,9 @@ class CopyOutputScalingPixelTest
renderer()->DecideRenderPassAllocationsForFrame(list);
renderer()->DrawFrame(&list, 1.0f, viewport_size,
gfx::DisplayColorSpaces());
+ // Call SwapBuffersSkipped(), so the renderer can release related
+ // resources.
+ renderer()->SwapBuffersSkipped();
loop.Run();
}
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc
index 647d33f7a2a..089e265f0f5 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.cc
+++ b/chromium/components/viz/service/display/dc_layer_overlay.cc
@@ -17,7 +17,6 @@
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_processor_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/config/gpu_finch_features.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index 15ac491792a..9691ccf8bed 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/direct_renderer.h"
+#include <limits.h>
#include <stddef.h>
#include <utility>
@@ -11,6 +12,7 @@
#include "base/auto_reset.h"
#include "base/containers/circular_deque.h"
+#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
@@ -465,6 +467,15 @@ void DirectRenderer::DrawFrame(
current_frame_valid_ = false;
}
+gfx::Rect DirectRenderer::GetTargetDamageBoundingRect() const {
+ gfx::Rect bounding_rect = output_surface_->GetCurrentFramebufferDamage();
+ if (overlay_processor_) {
+ bounding_rect.Union(
+ overlay_processor_->GetPreviousFrameOverlaysBoundingRect());
+ }
+ return bounding_rect;
+}
+
gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace() const {
gfx::Rect device_viewport_rect(current_frame()->device_viewport_size);
device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
@@ -808,48 +819,67 @@ gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass(
gfx::Rect root_damage_rect = current_frame()->root_damage_rect;
if (render_pass == root_render_pass) {
- auto display_area = current_frame()->device_viewport_size.GetArea();
- DCHECK(display_area);
-
- auto frame_buffer_damage = output_surface_->GetCurrentFramebufferDamage();
- auto root_damage_area = root_damage_rect.size().GetArea();
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.FrameBufferDamage",
- 100ull * frame_buffer_damage.size().GetArea() / display_area);
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.RootDamage",
- 100ull * root_damage_area / display_area);
-
- root_damage_rect.Union(frame_buffer_damage);
-
- // If the root damage rect intersects any child render pass that has a
- // pixel-moving backdrop-filter, expand the damage to include the entire
- // child pass. See crbug.com/986206 for context.
- if (!backdrop_filter_output_rects_.empty() && !root_damage_rect.IsEmpty()) {
- for (auto* quad : render_pass->quad_list) {
- if (quad->material == DrawQuad::Material::kRenderPass) {
- auto iter = backdrop_filter_output_rects_.find(
- RenderPassDrawQuad::MaterialCast(quad)->render_pass_id);
- if (iter != backdrop_filter_output_rects_.end()) {
- auto this_output_rect = iter->second;
- if (root_damage_rect.Intersects(this_output_rect))
- root_damage_rect.Union(this_output_rect);
+ base::CheckedNumeric<int> display_area =
+ current_frame()->device_viewport_size.GetCheckedArea();
+ gfx::Rect frame_buffer_damage =
+ output_surface_->GetCurrentFramebufferDamage();
+ base::CheckedNumeric<int> root_damage_area =
+ root_damage_rect.size().GetCheckedArea();
+ if (display_area.IsValid() && root_damage_area.IsValid()) {
+ DCHECK_GT(static_cast<int>(display_area.ValueOrDie()), 0);
+ {
+ base::CheckedNumeric<int> frame_buffer_damage_area =
+ frame_buffer_damage.size().GetCheckedArea();
+ int ratio =
+ (frame_buffer_damage_area / display_area).ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.FrameBufferDamage",
+ 100ull * ratio);
+ }
+ {
+ int ratio = (root_damage_area / display_area).ValueOrDie();
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.RootDamage",
+ 100ull * ratio);
+ }
+
+ root_damage_rect.Union(frame_buffer_damage);
+
+ // If the root damage rect intersects any child render pass that has a
+ // pixel-moving backdrop-filter, expand the damage to include the entire
+ // child pass. See crbug.com/986206 for context.
+ if (!backdrop_filter_output_rects_.empty() &&
+ !root_damage_rect.IsEmpty()) {
+ for (auto* quad : render_pass->quad_list) {
+ if (quad->material == DrawQuad::Material::kRenderPass) {
+ auto iter = backdrop_filter_output_rects_.find(
+ RenderPassDrawQuad::MaterialCast(quad)->render_pass_id);
+ if (iter != backdrop_filter_output_rects_.end()) {
+ gfx::Rect this_output_rect = iter->second;
+ if (root_damage_rect.Intersects(this_output_rect))
+ root_damage_rect.Union(this_output_rect);
+ }
}
}
}
- }
-
- // Total damage after all adjustments.
- auto total_damage_area = root_damage_rect.size().GetArea();
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.TotalDamage",
- 100ull * total_damage_area / display_area);
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.ExtraDamage",
- 100ull * (total_damage_area - root_damage_area) / display_area);
+ // Total damage after all adjustments.
+ base::CheckedNumeric<int> total_damage_area =
+ root_damage_rect.size().GetCheckedArea();
+ {
+ int ratio = (total_damage_area / display_area).ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.TotalDamage",
+ 100ull * ratio);
+ }
+ {
+ int ratio = ((total_damage_area - root_damage_area) / display_area)
+ .ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.ExtraDamage",
+ 100ull * ratio);
+ }
+ }
return root_damage_rect;
}
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index 259ec01ce1c..ef57383011a 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -69,6 +69,11 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
const gfx::Size& device_viewport_size,
const gfx::DisplayColorSpaces& display_color_spaces);
+ // The renderer might expand the damage (e.g: HW overlays were used,
+ // invalidation rects on previous buffers). This function returns a
+ // bounding rect of the area that might need to be recomposited.
+ gfx::Rect GetTargetDamageBoundingRect() const;
+
// Public interface implemented by subclasses.
struct SwapFrameData {
SwapFrameData();
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index 80382efd040..fd92ca7cfee 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -5,7 +5,9 @@
#include "components/viz/service/display/display.h"
#include <stddef.h>
+#include <algorithm>
#include <limits>
+#include <utility>
#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_macros.h"
@@ -55,6 +57,14 @@ namespace viz {
namespace {
+enum class TypeOfVideoInFrame {
+ kNoVideo = 0,
+ kVideo = 1,
+
+ // This should be the last entry/largest value above.
+ kMaxValue = kVideo,
+};
+
const DrawQuad::Material kNonSplittableMaterials[] = {
// Exclude debug quads from quad splitting
DrawQuad::Material::kDebugBorder,
@@ -97,8 +107,11 @@ gfx::PresentationFeedback SanitizePresentationFeedback(
// therefore the timestamp can be slightly in the future in comparison with
// base::TimeTicks::Now(). Such presentation feedbacks should not be rejected.
// See https://crbug.com/1040178
+ // Sometimes we snap the feedback's time stamp to the nearest vsync, and that
+ // can be offset by one vsync-internal. These feedback has kVSync set.
const auto allowed_delta_from_future =
- ((feedback.flags & gfx::PresentationFeedback::kHWClock) != 0)
+ ((feedback.flags & (gfx::PresentationFeedback::kHWClock |
+ gfx::PresentationFeedback::kVSync)) != 0)
? kAllowedDeltaFromFuture
: base::TimeDelta();
if (feedback.timestamp > now + allowed_delta_from_future) {
@@ -165,25 +178,41 @@ gfx::Rect SafeConvertRectForRegion(const gfx::Rect& r) {
return safe_rect;
}
-// Computes the accumulated area of all the rectangles in the list of |rects|.
-int ComputeArea(const std::vector<gfx::Rect>& rects) {
- int area = 0;
- for (const auto& r : rects)
- area += r.size().GetArea();
- return area;
-}
-
// Decides whether or not a DrawQuad should be split into a more complex visible
// region in order to avoid overdraw.
bool CanSplitQuad(const DrawQuad::Material m,
- const int visible_region_area,
- const int visible_region_bounding_area,
- const int minimum_fragments_reduced,
+ const std::vector<gfx::Rect>& visible_region_rects,
+ const gfx::Size& visible_region_bounding_size,
+ int minimum_fragments_reduced,
const float device_scale_factor) {
- return !base::Contains(kNonSplittableMaterials, m) &&
- (visible_region_bounding_area - visible_region_area) *
- device_scale_factor * device_scale_factor >
- minimum_fragments_reduced;
+ if (base::Contains(kNonSplittableMaterials, m))
+ return false;
+
+ base::CheckedNumeric<int> area = 0;
+ for (const auto& r : visible_region_rects) {
+ area += r.size().GetCheckedArea();
+ // In calculations below, assume false if this addition overflows.
+ if (!area.IsValid()) {
+ return false;
+ }
+ }
+
+ base::CheckedNumeric<int> visible_region_bounding_area =
+ visible_region_bounding_size.GetCheckedArea();
+ if (!visible_region_bounding_area.IsValid()) {
+ // In calculations below, assume true if this overflows.
+ return true;
+ }
+
+ area = visible_region_bounding_area - area;
+ if (!area.IsValid()) {
+ // In calculations below, assume false if this subtraction underflows.
+ return false;
+ }
+
+ int int_area = area.ValueOrDie();
+ return int_area * device_scale_factor * device_scale_factor >
+ minimum_fragments_reduced;
}
// Attempts to consolidate rectangles that were only split because of the
@@ -521,10 +550,13 @@ void Display::InitializeRenderer(bool enable_shared_images) {
// Outputting a partial list of quads might not work in cases where contents
// outside the damage rect might be needed by the renderer.
+ bool might_invalidate_outside_damage =
+ !output_surface_->capabilities().only_invalidates_damage_rect ||
+ overlay_processor_->IsOverlaySupported();
bool output_partial_list =
- output_surface_->capabilities().only_invalidates_damage_rect &&
renderer_->use_partial_swap() &&
- !overlay_processor_->IsOverlaySupported();
+ (!might_invalidate_outside_damage ||
+ output_surface_->capabilities().supports_target_damage);
aggregator_ = std::make_unique<SurfaceAggregator>(
surface_manager_, resource_provider_.get(), output_partial_list,
@@ -611,9 +643,32 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
{
FrameRateDecider::ScopedAggregate scoped_aggregate(
frame_rate_decider_.get());
- frame =
- aggregator_->Aggregate(current_surface_id_, expected_display_time,
- current_display_transform, ++swapped_trace_id_);
+ gfx::Rect target_damage_bounding_rect;
+ if (output_surface_->capabilities().supports_target_damage)
+ target_damage_bounding_rect = renderer_->GetTargetDamageBoundingRect();
+
+ frame = aggregator_->Aggregate(
+ current_surface_id_, expected_display_time, current_display_transform,
+ target_damage_bounding_rect, ++swapped_trace_id_);
+ }
+
+ // Records whether the aggregated frame contains video or not.
+ // TODO(vikassoni) : Extend this capability to record whether a video frame is
+ // inline or fullscreen.
+ UMA_HISTOGRAM_ENUMERATION("Compositing.SurfaceAggregator.FrameContainsVideo",
+ frame.metadata.may_contain_video
+ ? TypeOfVideoInFrame::kVideo
+ : TypeOfVideoInFrame::kNoVideo);
+
+ if (frame.metadata.delegated_ink_metadata) {
+ TRACE_EVENT_INSTANT2(
+ "viz", "Delegated Ink Metadata was aggregated for DrawAndSwap.",
+ TRACE_EVENT_SCOPE_THREAD, "point",
+ frame.metadata.delegated_ink_metadata->point().ToString(), "area",
+ frame.metadata.delegated_ink_metadata->presentation_area().ToString());
+ // TODO(1052145): This metadata will be stored here and used to determine
+ // which points should be drawn onto the back buffer (via Skia or OS APIs)
+ // before being swapped onto the screen.
}
#if defined(OS_ANDROID)
@@ -1039,9 +1094,12 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
settings_.kMaximumOccluderComplexity) {
gfx::Rect smallest_rect = *occlusion_in_target_space.begin();
for (const auto& occluding_rect : occlusion_in_target_space) {
- if (occluding_rect.size().GetArea() <
- smallest_rect.size().GetArea())
+ if (occluding_rect.size().GetCheckedArea().ValueOrDefault(
+ INT_MAX) <
+ smallest_rect.size().GetCheckedArea().ValueOrDefault(
+ INT_MAX)) {
smallest_rect = occluding_rect;
+ }
}
occlusion_in_target_space.Subtract(smallest_rect);
}
@@ -1130,8 +1188,8 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
!visible_region.Intersects(render_pass_quads_in_content_space) &&
ReduceComplexity(visible_region, settings_.quad_split_limit,
&cached_visible_region_) &&
- CanSplitQuad(quad->material, ComputeArea(cached_visible_region_),
- visible_region.bounds().size().GetArea(),
+ CanSplitQuad(quad->material, cached_visible_region_,
+ visible_region.bounds().size(),
settings_.minimum_fragments_reduced,
device_scale_factor_);
if (should_split_quads) {
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
index bcf21f8135b..faa7a2179be 100644
--- a/chromium/components/viz/service/display/display_resource_provider.cc
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -198,7 +198,7 @@ void DisplayResourceProvider::SendPromotionHints(
if (it->second.marked_for_deletion)
continue;
- const ChildResource* resource = LockForRead(id);
+ const ChildResource* resource = LockForRead(id, false /* overlay_only */);
// TODO(ericrk): We should never fail LockForRead, but we appear to be
// doing so on Android in rare cases. Handle this gracefully until a better
// solution can be found. https://crbug.com/811858
@@ -218,7 +218,7 @@ void DisplayResourceProvider::SendPromotionHints(
promotable ? iter->second.width() : 0,
promotable ? iter->second.height() : 0);
}
- UnlockForRead(id);
+ UnlockForRead(id, false /* overlay_only */);
}
#endif
}
@@ -493,7 +493,7 @@ GLES2Interface* DisplayResourceProvider::ContextGL() const {
}
const DisplayResourceProvider::ChildResource*
-DisplayResourceProvider::LockForRead(ResourceId id) {
+DisplayResourceProvider::LockForRead(ResourceId id, bool overlay_only) {
// TODO(ericrk): We should never fail TryGetResource, but we appear to be
// doing so on Android in rare cases. Handle this gracefully until a better
// solution can be found. https://crbug.com/811858
@@ -519,10 +519,27 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
}
resource->SetLocallyUsed();
}
- if (mailbox.IsSharedImage() && enable_shared_images_ &&
- resource->lock_for_read_count == 0) {
- gl->BeginSharedImageAccessDirectCHROMIUM(
- resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
+ if (mailbox.IsSharedImage() && enable_shared_images_) {
+ if (overlay_only) {
+ if (resource->lock_for_overlay_count == 0) {
+ // If |lock_for_read_count| > 0, then BeginSharedImageAccess has
+ // already been called with READ, so don't re-lock with OVERLAY.
+ if (resource->lock_for_read_count == 0) {
+ gl->BeginSharedImageAccessDirectCHROMIUM(
+ resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_OVERLAY_CHROMIUM);
+ }
+ }
+ } else {
+ if (resource->lock_for_read_count == 0) {
+ // If |lock_for_overlay_count| > 0, then we have already begun access
+ // for OVERLAY. End this access and "upgrade" it to READ.
+ // See https://crbug.com/1113925 for how this can go wrong.
+ if (resource->lock_for_overlay_count > 0)
+ gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
+ gl->BeginSharedImageAccessDirectCHROMIUM(
+ resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
+ }
+ }
}
}
@@ -540,7 +557,10 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
}
}
- resource->lock_for_read_count++;
+ if (overlay_only)
+ resource->lock_for_overlay_count++;
+ else
+ resource->lock_for_read_count++;
if (resource->transferable.read_lock_fences_enabled) {
if (current_read_lock_fence_.get())
current_read_lock_fence_->Set();
@@ -550,7 +570,7 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
return resource;
}
-void DisplayResourceProvider::UnlockForRead(ResourceId id) {
+void DisplayResourceProvider::UnlockForRead(ResourceId id, bool overlay_only) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto it = resources_.find(id);
// TODO(ericrk): We should never fail to find id, but we appear to be
@@ -560,16 +580,23 @@ void DisplayResourceProvider::UnlockForRead(ResourceId id) {
return;
ChildResource* resource = &it->second;
- DCHECK_GT(resource->lock_for_read_count, 0);
if (resource->transferable.mailbox_holder.mailbox.IsSharedImage() &&
- resource->is_gpu_resource_type() && enable_shared_images_ &&
- resource->lock_for_read_count == 1) {
- DCHECK(resource->gl_id);
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
+ resource->is_gpu_resource_type() && enable_shared_images_) {
+ // If this is the last READ or OVERLAY access, then end access.
+ if (resource->lock_for_read_count + resource->lock_for_overlay_count == 1) {
+ DCHECK(resource->gl_id);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
+ }
+ }
+ if (overlay_only) {
+ DCHECK_GT(resource->lock_for_overlay_count, 0);
+ resource->lock_for_overlay_count--;
+ } else {
+ DCHECK_GT(resource->lock_for_read_count, 0);
+ resource->lock_for_read_count--;
}
- resource->lock_for_read_count--;
TryReleaseResource(id, resource);
}
@@ -851,7 +878,8 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
DisplayResourceProvider* resource_provider,
ResourceId resource_id)
: resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource = resource_provider->LockForRead(resource_id);
+ const ChildResource* resource =
+ resource_provider->LockForRead(resource_id, false /* overlay_only */);
// TODO(ericrk): We should never fail LockForRead, but we appear to be
// doing so on Android in rare cases. Handle this gracefully until a better
// solution can be found. https://crbug.com/811858
@@ -865,7 +893,23 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
}
DisplayResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
- resource_provider_->UnlockForRead(resource_id_);
+ resource_provider_->UnlockForRead(resource_id_, false /* overlay_only */);
+}
+
+DisplayResourceProvider::ScopedOverlayLockGL::ScopedOverlayLockGL(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id)
+ : resource_provider_(resource_provider), resource_id_(resource_id) {
+ const ChildResource* resource =
+ resource_provider->LockForRead(resource_id, true /* overlay_only */);
+ if (!resource)
+ return;
+
+ texture_id_ = resource->gl_id;
+}
+
+DisplayResourceProvider::ScopedOverlayLockGL::~ScopedOverlayLockGL() {
+ resource_provider_->UnlockForRead(resource_id_, true /* overlay_only */);
}
DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
@@ -893,7 +937,8 @@ DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
SkAlphaType alpha_type,
GrSurfaceOrigin origin)
: resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource = resource_provider->LockForRead(resource_id);
+ const ChildResource* resource =
+ resource_provider->LockForRead(resource_id, false /* overlay_only */);
DCHECK(resource);
// Use cached SkImage if possible.
@@ -942,7 +987,7 @@ DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
}
DisplayResourceProvider::ScopedReadLockSkImage::~ScopedReadLockSkImage() {
- resource_provider_->UnlockForRead(resource_id_);
+ resource_provider_->UnlockForRead(resource_id_, false /* overlay_only */);
}
DisplayResourceProvider::ScopedReadLockSharedImage::ScopedReadLockSharedImage(
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
index 71abecc9fd6..2b5c0a95167 100644
--- a/chromium/components/viz/service/display/display_resource_provider.h
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -158,6 +158,23 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
gfx::ColorSpace color_space_;
};
+ class VIZ_SERVICE_EXPORT ScopedOverlayLockGL {
+ public:
+ ScopedOverlayLockGL(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+ ~ScopedOverlayLockGL();
+
+ ScopedOverlayLockGL(const ScopedOverlayLockGL&) = delete;
+ ScopedOverlayLockGL& operator=(const ScopedOverlayLockGL&) = delete;
+
+ GLuint texture_id() const { return texture_id_; }
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ const ResourceId resource_id_;
+ GLuint texture_id_ = 0;
+ };
+
class VIZ_SERVICE_EXPORT ScopedSamplerGL {
public:
ScopedSamplerGL(DisplayResourceProvider* resource_provider,
@@ -521,8 +538,8 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
// Returns null if we do not have a ContextProvider.
gpu::gles2::GLES2Interface* ContextGL() const;
- const ChildResource* LockForRead(ResourceId id);
- void UnlockForRead(ResourceId id);
+ const ChildResource* LockForRead(ResourceId id, bool overlay_only);
+ void UnlockForRead(ResourceId id, bool overlay_only);
void TryReleaseResource(ResourceId id, ChildResource* resource);
// Binds the given GL resource to a texture target for sampling using the
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index 94f6984ba7f..58082642162 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -36,6 +36,7 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "components/viz/test/test_gles2_interface.h"
+#include "components/viz/test/viz_test_suite.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -102,8 +103,11 @@ class StubDisplayClient : public DisplayClient {
}
};
-void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
+void CopyCallback(bool* called,
+ base::OnceClosure finished,
+ std::unique_ptr<CopyOutputResult> result) {
*called = true;
+ std::move(finished).Run();
}
gfx::SwapTimings GetTestSwapTimings() {
@@ -214,10 +218,7 @@ class DisplayTest : public testing::Test {
void ResetDamageForTest() { scheduler_->ResetDamageForTest(); }
- void RunAllPendingInMessageLoop() {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ void RunUntilIdle() { VizTestSuite::RunUntilIdle(); }
void LatencyInfoCapTest(bool over_capacity);
@@ -424,10 +425,12 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass = RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 100, 100);
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ base::RunLoop copy_run_loop;
bool copy_called = false;
pass->copy_requests.push_back(std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyCallback, &copy_called)));
+ base::BindOnce(&CopyCallback, &copy_called,
+ copy_run_loop.QuitClosure())));
pass->id = 1u;
pass_list.push_back(std::move(pass));
@@ -441,6 +444,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
display_->DrawAndSwap(base::TimeTicks::Now());
EXPECT_TRUE(scheduler_->swapped());
EXPECT_EQ(5u, output_surface_->num_sent_frames());
+ copy_run_loop.Run();
EXPECT_TRUE(copy_called);
}
@@ -3543,7 +3547,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
pass_list.push_back(std::move(pass));
SubmitCompositorFrame(&pass_list, local_surface_id);
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
}
{
@@ -3557,7 +3561,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
sub_support->SubmitCompositorFrame(sub_local_surface_id, std::move(frame));
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
// Both frames with frame-tokens 1 and 2 requested presentation-feedback.
ASSERT_EQ(2u, sub_support->timing_details().size());
@@ -3575,7 +3579,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
sub_support->SubmitCompositorFrame(sub_local_surface_id, std::move(frame));
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
}
}
@@ -4500,10 +4504,12 @@ TEST_F(DisplayTest, DisplaySizeMismatch) {
std::unique_ptr<RenderPass> pass = RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 99, 99);
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ base::RunLoop copy_run_loop;
bool copy_called = false;
pass->copy_requests.push_back(std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyCallback, &copy_called)));
+ base::BindOnce(&CopyCallback, &copy_called,
+ copy_run_loop.QuitClosure())));
pass->id = 1u;
RenderPassList pass_list;
@@ -4516,6 +4522,8 @@ TEST_F(DisplayTest, DisplaySizeMismatch) {
display_->DrawAndSwap(base::TimeTicks::Now());
+ copy_run_loop.Run();
+
// Expect no swap happen
EXPECT_EQ(0u, output_surface_->num_sent_frames());
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
index 1efef996517..591e5c4e6f7 100644
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -83,6 +83,10 @@
#include "ui/gfx/rrect_f.h"
#include "ui/gfx/skia_util.h"
+#if defined(USE_X11)
+#include "ui/base/ui_base_features.h"
+#endif
+
using gpu::gles2::GLES2Interface;
namespace viz {
@@ -2826,7 +2830,12 @@ void GLRenderer::FinishDrawingFrame() {
ScheduleOutputSurfaceAsOverlay();
#if defined(OS_ANDROID) || defined(USE_OZONE)
- ScheduleOverlays();
+ bool schedule_overlays = true;
+#if defined(USE_X11)
+ schedule_overlays = features::IsUsingOzonePlatform();
+#endif
+ if (schedule_overlays)
+ ScheduleOverlays();
#elif defined(OS_MACOSX)
ScheduleCALayers();
#elif defined(OS_WIN)
@@ -2855,8 +2864,9 @@ void GLRenderer::FinishDrawingQuadList() {
// Use the current surface area as max result. The effect is that overdraw
// is reported as a percentage of the output surface size. ie. 2x overdraw
// for the whole screen is reported as 200.
- const int surface_area = current_surface_size_.GetArea();
- DCHECK_GT(surface_area, 0);
+ base::CheckedNumeric<int> surface_area =
+ current_surface_size_.GetCheckedArea();
+ DCHECK_GT(static_cast<int>(surface_area.ValueOrDefault(INT_MAX)), 0);
gl_->EndQueryEXT(GL_SAMPLES_PASSED_ARB);
context_support_->SignalQuery(
@@ -3528,7 +3538,7 @@ void GLRenderer::ScheduleCALayers() {
unsigned texture_id = 0;
if (contents_resource_id) {
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, contents_resource_id));
texture_id = pending_overlay_resources_.back()->texture_id();
}
@@ -3585,7 +3595,7 @@ void GLRenderer::ScheduleDCLayers() {
if (resource_id == kInvalidResourceId)
break;
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, resource_id));
texture_ids[i] = pending_overlay_resources_.back()->texture_id();
}
@@ -3624,7 +3634,7 @@ void GLRenderer::ScheduleOverlays() {
OverlayCandidateList& overlays = current_frame()->overlay_list;
for (const auto& overlay_candidate : overlays) {
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, overlay_candidate.resource_id));
unsigned texture_id = pending_overlay_resources_.back()->texture_id();
@@ -3981,7 +3991,7 @@ void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) {
}
}
-void GLRenderer::ProcessOverdrawFeedback(int surface_area,
+void GLRenderer::ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
unsigned occlusion_query) {
unsigned result = 0;
DCHECK(occlusion_query);
@@ -3990,7 +4000,8 @@ void GLRenderer::ProcessOverdrawFeedback(int surface_area,
// Report GPU overdraw as a percentage of |surface_area|.
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"), "GPU Overdraw",
- (result * 100.0 / surface_area));
+ (result * 100.0 /
+ static_cast<int>(surface_area.ValueOrDefault(INT_MAX))));
}
void GLRenderer::UpdateRenderPassTextures(
@@ -4041,8 +4052,11 @@ void GLRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
auto contents_texture_it = render_pass_textures_.find(render_pass_id);
- if (contents_texture_it != render_pass_textures_.end())
+ if (contents_texture_it != render_pass_textures_.end()) {
+ DCHECK(gfx::Rect(contents_texture_it->second.size())
+ .Contains(gfx::Rect(requirements.size)));
return;
+ }
ScopedRenderPassTexture contents_texture(
output_surface_->context_provider(), requirements.size,
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
index f4943ca0721..94e7a088b39 100644
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -155,7 +155,7 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
friend class GLRendererTest;
using OverlayResourceLock =
- std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>;
+ std::unique_ptr<DisplayResourceProvider::ScopedOverlayLockGL>;
using OverlayResourceLockList = std::vector<OverlayResourceLock>;
// If a RenderPass is used as an overlay, we render the RenderPass with any
@@ -351,7 +351,8 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
void SetupOverdrawFeedback();
// Process overdraw feedback from query.
- void ProcessOverdrawFeedback(int surface_area, unsigned query);
+ void ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
+ unsigned query);
bool OverdrawTracingEnabled();
ResourceFormat CurrentRenderPassResourceFormat() const;
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc
index cd54ec7f65b..eca6218676e 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/process/memory.h"
#include "base/stl_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
@@ -215,7 +216,9 @@ void GLRendererCopier::CopyFromTextureOrFramebuffer(
// requires that the result be accessed via a task in the same task runner
// sequence as the GLRendererCopier. Since I420_PLANES requests are meant
// to be VIZ-internal, this is an acceptable limitation to enforce.
- DCHECK(request->SendsResultsInCurrentSequence() || async_gl_task_runner_);
+ if (!request->SendsResultsInCurrentSequence() && !async_gl_task_runner_) {
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
+ }
const gfx::Rect aligned_rect = RenderI420Textures(
*request, flipped_source, color_space, source_texture,
@@ -508,9 +511,10 @@ class ReadPixelsWorkflow {
// Create a buffer for the pixel transfer.
gl->GenBuffers(1, &transfer_buffer_);
gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- gl->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- kRGBABytesPerPixel * result_rect.size().GetArea(), nullptr,
- GL_STREAM_READ);
+ gl->BufferData(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ (result_rect.size().GetCheckedArea() * kRGBABytesPerPixel).ValueOrDie(),
+ nullptr, GL_STREAM_READ);
// Execute an asynchronous read-pixels operation, with a query that triggers
// when Finish() should be run.
@@ -749,13 +753,15 @@ class ReadI420PlanesWorkflow
auto* const gl = context_provider_->ContextGL();
gl->GenBuffers(1, &transfer_buffer_);
gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- const int y_plane_bytes = kRGBABytesPerPixel * y_texture_size().GetArea();
- const int chroma_plane_bytes =
- kRGBABytesPerPixel * chroma_texture_size().GetArea();
+ base::CheckedNumeric<int> y_plane_bytes =
+ y_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
+ base::CheckedNumeric<int> chroma_plane_bytes =
+ chroma_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
gl->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- y_plane_bytes + 2 * chroma_plane_bytes, nullptr,
- GL_STREAM_READ);
- data_offsets_ = {0, y_plane_bytes, y_plane_bytes + chroma_plane_bytes};
+ (y_plane_bytes + chroma_plane_bytes * 2).ValueOrDie(),
+ nullptr, GL_STREAM_READ);
+ data_offsets_ = {0, y_plane_bytes.ValueOrDie(),
+ (y_plane_bytes + chroma_plane_bytes).ValueOrDie()};
gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
// Generate the three queries used for determining when each of the plane
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
index aebb5ed5d56..fb3452b9e0f 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
@@ -113,7 +113,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const base::UnguessableToken no_source;
EXPECT_EQ(0u, GetCopierCacheSize());
auto things = TakeReusableThingsOrCreate(no_source);
- EXPECT_TRUE(!!things);
+ EXPECT_TRUE(things);
StashReusableThingsOrDelete(no_source, std::move(things));
EXPECT_EQ(nullptr, PeekReusableThings(no_source));
EXPECT_EQ(0u, GetCopierCacheSize());
@@ -122,7 +122,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const auto source = base::UnguessableToken::Create();
things = TakeReusableThingsOrCreate(source);
ReusableThings* things_raw_ptr = things.get();
- EXPECT_TRUE(!!things_raw_ptr);
+ EXPECT_TRUE(things_raw_ptr);
StashReusableThingsOrDelete(source, std::move(things));
EXPECT_EQ(things_raw_ptr, PeekReusableThings(source));
EXPECT_EQ(1u, GetCopierCacheSize());
@@ -131,7 +131,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const auto source2 = base::UnguessableToken::Create();
things = TakeReusableThingsOrCreate(source2);
things_raw_ptr = things.get();
- EXPECT_TRUE(!!things_raw_ptr);
+ EXPECT_TRUE(things_raw_ptr);
EXPECT_EQ(1u, GetCopierCacheSize());
StashReusableThingsOrDelete(source2, std::move(things));
EXPECT_EQ(things_raw_ptr, PeekReusableThings(source2));
@@ -144,14 +144,14 @@ TEST_F(GLRendererCopierTest, FreesUnusedResources) {
const base::UnguessableToken source = base::UnguessableToken::Create();
EXPECT_EQ(0u, GetCopierCacheSize());
StashReusableThingsOrDelete(source, TakeReusableThingsOrCreate(source));
- EXPECT_TRUE(!!PeekReusableThings(source));
+ EXPECT_TRUE(PeekReusableThings(source));
EXPECT_EQ(1u, GetCopierCacheSize());
// Call FreesUnusedCachedResources() the maximum number of times before the
// cache entry would be considered for freeing.
for (int i = 0; i < kKeepalivePeriod - 1; ++i) {
FreeUnusedCachedResources();
- EXPECT_TRUE(!!PeekReusableThings(source));
+ EXPECT_TRUE(PeekReusableThings(source));
EXPECT_EQ(1u, GetCopierCacheSize());
if (HasFailure())
break;
@@ -160,7 +160,7 @@ TEST_F(GLRendererCopierTest, FreesUnusedResources) {
// Calling FreeUnusedCachedResources() just one more time should cause the
// cache entry to be freed.
FreeUnusedCachedResources();
- EXPECT_FALSE(!!PeekReusableThings(source));
+ EXPECT_FALSE(PeekReusableThings(source));
EXPECT_EQ(0u, GetCopierCacheSize());
}
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
index a698822e170..6e7ecb769eb 100644
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -37,6 +37,7 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_gles2_interface.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
+#include "components/viz/test/viz_test_suite.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/config/gpu_finch_features.h"
@@ -85,6 +86,11 @@ MATCHER_P(MatchesSyncToken, sync_token, "") {
class GLRendererTest : public testing::Test {
protected:
+ ~GLRendererTest() override {
+ // Some tests create CopyOutputRequests which will PostTask ensure
+ // they are all cleaned up and completed before destroying the test.
+ VizTestSuite::RunUntilIdle();
+ }
RenderPass* root_render_pass() {
return render_passes_in_draw_order_.back().get();
}
diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h
index 6476ec148f2..b58adf77f08 100644
--- a/chromium/components/viz/service/display/output_surface.h
+++ b/chromium/components/viz/service/display/output_surface.h
@@ -9,7 +9,6 @@
#include <vector>
#include "base/callback_helpers.h"
-#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
@@ -57,6 +56,10 @@ class VIZ_SERVICE_EXPORT OutputSurface {
Capabilities(const Capabilities& capabilities);
int max_frames_pending = 1;
+ // The number of buffers for the SkiaOutputDevice. If the
+ // |supports_post_sub_buffer| true, SkiaOutputSurfaceImpl will track target
+ // damaged area based on this number.
+ int number_of_buffers = 2;
// Whether this output surface renders to the default OpenGL zero
// framebuffer or to an offscreen framebuffer.
bool uses_default_gl_framebuffer = true;
@@ -88,6 +91,9 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// When this is false contents outside the damaged area might need to be
// recomposited to the surface.
bool only_invalidates_damage_rect = true;
+ // Whether OutputSurface::GetTargetDamageBoundingRect is implemented and
+ // will return a bounding rectangle of the target buffer invalidated area.
+ bool supports_target_damage = false;
// Whether the gpu supports surfaceless surface (equivalent of using buffer
// queue).
bool supports_surfaceless = false;
@@ -96,6 +102,10 @@ class VIZ_SERVICE_EXPORT OutputSurface {
bool android_surface_control_feature_enabled = false;
// True if the buffer content will be preserved after presenting.
bool preserve_buffer_content = false;
+ // True if the SkiaOutputDevice will set
+ // SwapBuffersCompleteParams::frame_buffer_damage_area for every
+ // SwapBuffers complete callback.
+ bool damage_area_from_skia_output_device = false;
// The SkColorType and GrBackendFormat for non-HDR and HDR.
// TODO(penghuang): remove SkColorType and GrBackendFormat when
// OutputSurface uses the |format| passed to Reshape().
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.cc b/chromium/components/viz/service/display/overlay_processor_interface.cc
index 5f9990fbd50..f09e8ac00fb 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.cc
+++ b/chromium/components/viz/service/display/overlay_processor_interface.cc
@@ -8,6 +8,7 @@
#include "base/metrics/histogram_macros.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/features.h"
+#include "components/viz/service/display/overlay_processor_stub.h"
#if defined(OS_MACOSX)
#include "components/viz/service/display/overlay_processor_mac.h"
@@ -18,10 +19,9 @@
#include "components/viz/service/display/overlay_processor_surface_control.h"
#elif defined(USE_OZONE)
#include "components/viz/service/display/overlay_processor_ozone.h"
+#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/overlay_manager_ozone.h"
#include "ui/ozone/public/ozone_platform.h"
-#else
-#include "components/viz/service/display/overlay_processor_stub.h"
#endif
namespace viz {
@@ -98,6 +98,8 @@ OverlayProcessorInterface::CreateOverlayProcessor(
enable_dc_overlay,
std::make_unique<DCLayerOverlayProcessor>(renderer_settings)));
#elif defined(USE_OZONE)
+ if (!features::IsUsingOzonePlatform())
+ return std::make_unique<OverlayProcessorStub>();
bool overlay_enabled = surface_handle != gpu::kNullSurfaceHandle;
overlay_enabled &= !renderer_settings.overlay_strategies.empty();
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates;
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.h b/chromium/components/viz/service/display/overlay_processor_interface.h
index c5db304223f..e1779e03646 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.h
+++ b/chromium/components/viz/service/display/overlay_processor_interface.h
@@ -107,6 +107,10 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
virtual ~OverlayProcessorInterface() {}
virtual bool IsOverlaySupported() const = 0;
+ // Returns a bounding rectangle of the last set of overlay planes scheduled.
+ // It's expected to be called after ProcessForOverlays at frame N-1 has been
+ // called and before GetAndResetOverlayDamage at frame N.
+ virtual gfx::Rect GetPreviousFrameOverlaysBoundingRect() const = 0;
virtual gfx::Rect GetAndResetOverlayDamage() = 0;
// Returns true if the platform supports hw overlays and surface occluding
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.cc b/chromium/components/viz/service/display/overlay_processor_mac.cc
index d972c9873dd..2a3b10b4336 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.cc
+++ b/chromium/components/viz/service/display/overlay_processor_mac.cc
@@ -37,6 +37,12 @@ bool OverlayProcessorMac::IsOverlaySupported() const {
return could_overlay_;
}
+gfx::Rect OverlayProcessorMac::GetPreviousFrameOverlaysBoundingRect() const {
+ // TODO(dcastagna): Implement me.
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
gfx::Rect OverlayProcessorMac::GetAndResetOverlayDamage() {
gfx::Rect result = ca_overlay_damage_rect_;
ca_overlay_damage_rect_ = gfx::Rect();
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.h b/chromium/components/viz/service/display/overlay_processor_mac.h
index 03a8112ad4f..26e583a2b6b 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.h
+++ b/chromium/components/viz/service/display/overlay_processor_mac.h
@@ -35,6 +35,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
bool DisableSplittingQuads() const override;
bool IsOverlaySupported() const override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const override;
gfx::Rect GetAndResetOverlayDamage() override;
// Returns true if the platform supports hw overlays and surface occluding
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.cc b/chromium/components/viz/service/display/overlay_processor_ozone.cc
index 9dc16e17d09..9f3e7ef0679 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/overlay_processor_ozone.h"
+#include "base/logging.h"
#include "components/viz/common/features.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.cc b/chromium/components/viz/service/display/overlay_processor_stub.cc
index 799083887a6..0be55eec1c4 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.cc
+++ b/chromium/components/viz/service/display/overlay_processor_stub.cc
@@ -11,6 +11,10 @@ bool OverlayProcessorStub::IsOverlaySupported() const {
gfx::Rect OverlayProcessorStub::GetAndResetOverlayDamage() {
return gfx::Rect();
}
+gfx::Rect OverlayProcessorStub::GetPreviousFrameOverlaysBoundingRect() const {
+ return gfx::Rect();
+}
+
bool OverlayProcessorStub::NeedsSurfaceOccludingDamageRect() const {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.h b/chromium/components/viz/service/display/overlay_processor_stub.h
index 92069a7e077..1dee0517889 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.h
+++ b/chromium/components/viz/service/display/overlay_processor_stub.h
@@ -18,6 +18,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorStub
// Overrides OverlayProcessorInterface's pure virtual functions.
bool IsOverlaySupported() const final;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const final;
gfx::Rect GetAndResetOverlayDamage() final;
bool NeedsSurfaceOccludingDamageRect() const final;
void ProcessForOverlays(
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
index a218f08c331..86b00f87f22 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -35,6 +35,13 @@ OverlayProcessorUsingStrategy::OverlayProcessorUsingStrategy()
OverlayProcessorUsingStrategy::~OverlayProcessorUsingStrategy() = default;
+gfx::Rect OverlayProcessorUsingStrategy::GetPreviousFrameOverlaysBoundingRect()
+ const {
+ gfx::Rect result = overlay_damage_rect_;
+ result.Union(previous_frame_underlay_rect_);
+ return result;
+}
+
gfx::Rect OverlayProcessorUsingStrategy::GetAndResetOverlayDamage() {
gfx::Rect result = overlay_damage_rect_;
overlay_damage_rect_ = gfx::Rect();
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.h b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
index f946919c378..faa34d1b99b 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
@@ -66,6 +66,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
~OverlayProcessorUsingStrategy() override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const final;
gfx::Rect GetAndResetOverlayDamage() final;
// Override OverlayProcessor.
diff --git a/chromium/components/viz/service/display/overlay_processor_win.cc b/chromium/components/viz/service/display/overlay_processor_win.cc
index ffa85923c69..9c5b852fb69 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.cc
+++ b/chromium/components/viz/service/display/overlay_processor_win.cc
@@ -27,6 +27,12 @@ bool OverlayProcessorWin::IsOverlaySupported() const {
return enable_dc_overlay_;
}
+gfx::Rect OverlayProcessorWin::GetPreviousFrameOverlaysBoundingRect() const {
+ // TODO(dcastagna): Implement me.
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
gfx::Rect OverlayProcessorWin::GetAndResetOverlayDamage() {
return gfx::Rect();
}
diff --git a/chromium/components/viz/service/display/overlay_processor_win.h b/chromium/components/viz/service/display/overlay_processor_win.h
index f7863ad20da..95147c7dfc3 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.h
+++ b/chromium/components/viz/service/display/overlay_processor_win.h
@@ -34,6 +34,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorWin
~OverlayProcessorWin() override;
bool IsOverlaySupported() const override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const override;
gfx::Rect GetAndResetOverlayDamage() override;
// Returns true if the platform supports hw overlays and surface occluding
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 4d1fda11a4b..5436d5dea3c 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -6,6 +6,7 @@
#include "base/containers/adapters.h"
#include "base/lazy_instance.h"
+#include "base/logging.h"
#include "base/unguessable_token.h"
#include "build/chromecast_buildflags.h"
#include "components/viz/common/quads/draw_quad.h"
diff --git a/chromium/components/viz/service/display/program_binding.cc b/chromium/components/viz/service/display/program_binding.cc
index 0c246b056d8..975d1d01845 100644
--- a/chromium/components/viz/service/display/program_binding.cc
+++ b/chromium/components/viz/service/display/program_binding.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/program_binding.h"
+#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/service/display/geometry_binding.h"
#include "gpu/GLES2/gl2extchromium.h"
diff --git a/chromium/components/viz/service/display/program_binding.h b/chromium/components/viz/service/display/program_binding.h
index 19bf651da6a..bba6169e8ab 100644
--- a/chromium/components/viz/service/display/program_binding.h
+++ b/chromium/components/viz/service/display/program_binding.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/context_provider.h"
diff --git a/chromium/components/viz/service/display/renderer_perftest.cc b/chromium/components/viz/service/display/renderer_perftest.cc
index 27ac29e25c9..19a0a751da4 100644
--- a/chromium/components/viz/service/display/renderer_perftest.cc
+++ b/chromium/components/viz/service/display/renderer_perftest.cc
@@ -58,6 +58,7 @@
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_implementation.h"
namespace viz {
@@ -296,6 +297,7 @@ class RendererPerfTest : public testing::Test {
GpuServiceImpl* gpu_service);
void SetUp() override {
+ enable_pixel_output_ = std::make_unique<gl::DisableNullDrawGLBindings>();
renderer_settings_.use_skia_renderer =
std::is_base_of<SkiaRenderer, RendererType>::value;
if (renderer_settings_.use_skia_renderer)
@@ -685,6 +687,7 @@ class RendererPerfTest : public testing::Test {
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::vector<TransferableResource> resource_list_;
base::LapTimer timer_;
+ std::unique_ptr<gl::DisableNullDrawGLBindings> enable_pixel_output_;
DISALLOW_COPY_AND_ASSIGN(RendererPerfTest);
};
diff --git a/chromium/components/viz/service/display/shader.h b/chromium/components/viz/service/display/shader.h
index 6d154b623cb..f64ae804946 100644
--- a/chromium/components/viz/service/display/shader.h
+++ b/chromium/components/viz/service/display/shader.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "components/viz/service/viz_service_export.h"
diff --git a/chromium/components/viz/service/display/skia_readback_pixeltest.cc b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
index 93264575e8c..d2f1b7cc176 100644
--- a/chromium/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
@@ -199,6 +199,9 @@ TEST_P(SkiaReadbackPixelTest, ExecutesCopyRequest) {
renderer_->DecideRenderPassAllocationsForFrame(pass_list);
renderer_->DrawFrame(&pass_list, 1.0f, kSourceSize,
gfx::DisplayColorSpaces());
+ // Call SwapBuffersSkipped(), so the renderer can have a chance to release
+ // resources.
+ renderer_->SwapBuffersSkipped();
loop.Run();
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index 4a56dcc9a10..cff81b3c901 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/bits.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/trace_event.h"
@@ -63,6 +64,10 @@
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#endif
+
namespace viz {
namespace {
@@ -836,8 +841,6 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
switch (draw_mode_) {
case DrawMode::DDL: {
root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
- // TODO(https://crbug.com/1038107): Handle BeginPaintCurrentFrame() fail.
- CHECK(root_canvas_);
break;
}
case DrawMode::SKPRECORD: {
@@ -1119,12 +1122,25 @@ void SkiaRenderer::PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
}
}
+ if (rpdq_params.mask_image.get()) {
+ // The old behavior (in skia) was to filter the clipmask based on the
+ // setting in the layer's paint. Now we can set that to whatever we want
+ // when we make the clip-shader. For now, I will replicate the old (impl)
+ // logic.
+ SkFilterQuality filtering =
+ layer_paint.getFilterQuality() == kNone_SkFilterQuality
+ ? kNone_SkFilterQuality
+ : kLow_SkFilterQuality;
+ current_canvas_->save();
+ current_canvas_->clipShader(rpdq_params.mask_image->makeShader(
+ SkTileMode::kClamp, SkTileMode::kClamp,
+ &rpdq_params.mask_to_quad_matrix, filtering));
+ }
SkRect bounds = gfx::RectFToSkRect(rpdq_params.bypass_clip.has_value()
? *rpdq_params.bypass_clip
: params->visible_rect);
- current_canvas_->saveLayer(SkCanvas::SaveLayerRec(
- &bounds, &layer_paint, backdrop_filter.get(),
- rpdq_params.mask_image.get(), &rpdq_params.mask_to_quad_matrix, 0));
+ current_canvas_->saveLayer(
+ SkCanvas::SaveLayerRec(&bounds, &layer_paint, backdrop_filter.get(), 0));
// If we have backdrop filtered content (and not transparent black like with
// regular render passes), we have to clear out the parts of the layer that
@@ -2167,11 +2183,47 @@ void SkiaRenderer::ScheduleOverlays() {
}
skia_output_surface_->ScheduleOverlays(
std::move(current_frame()->overlay_list), std::move(sync_tokens));
-#elif defined(OS_MACOSX) || defined(USE_OZONE)
+#elif defined(OS_MACOSX)
+ DCHECK(output_surface_->capabilities().supports_surfaceless);
+ auto& locks = pending_overlay_locks_.back();
+ std::vector<gpu::SyncToken> sync_tokens;
+ for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
+ // Some overlays are for solid-color layers.
+ if (!ca_layer_overlay.contents_resource_id)
+ continue;
+
+ // TODO(https://crbug.com/894929): Track IOSurface in-use instead of just
+ // unlocking after the next SwapBuffers is completed.
+ locks.emplace_back(resource_provider_,
+ ca_layer_overlay.contents_resource_id);
+ auto& lock = locks.back();
+
+ // Sync tokens ensure the texture to be overlaid is available before
+ // scheduling it for display.
+ if (lock.sync_token().HasData())
+ sync_tokens.push_back(lock.sync_token());
+
+ // Populate the |mailbox| of the CALayerOverlay which will be used to look
+ // up the corresponding GLImageIOSurface when building the CALayer tree.
+ ca_layer_overlay.mailbox = lock.mailbox();
+ DCHECK(!ca_layer_overlay.mailbox.IsZero());
+ }
+ skia_output_surface_->ScheduleOverlays(
+ std::move(current_frame()->overlay_list), std::move(sync_tokens));
+#elif defined(USE_OZONE)
+ // For platforms that don't support overlays, the
+ // current_frame()->overlay_list should be empty, and this code should not be
+ // reached.
+ if (!features::IsUsingOzonePlatform()) {
+ NOTREACHED();
+ return;
+ }
+
NOTIMPLEMENTED_LOG_ONCE();
#else
- // For platforms doesn't support overlays, the current_frame()->overlay_list
- // should be empty, and here should not be reached.
+ // For platforms that don't support overlays, the
+ // current_frame()->overlay_list should be empty, and this code should not be
+ // reached.
NOTREACHED();
#endif
}
@@ -2411,6 +2463,10 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad,
}
}
+ if (!content_image) {
+ return;
+ }
+
// If the RP generated mipmaps when it was created, set quality to medium,
// which turns on mipmap filtering in Skia.
if (backing.generate_mipmap)
@@ -2562,8 +2618,10 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
auto it = render_pass_backings_.find(render_pass_id);
- if (it != render_pass_backings_.end())
+ if (it != render_pass_backings_.end()) {
+ DCHECK(gfx::Rect(it->second.size).Contains(gfx::Rect(requirements.size)));
return;
+ }
// TODO(penghuang): check supported format correctly.
gpu::Capabilities caps;
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index ebbaa150688..3321bf0001a 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -925,8 +925,11 @@ void SoftwareRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
auto it = render_pass_bitmaps_.find(render_pass_id);
- if (it != render_pass_bitmaps_.end())
+ if (it != render_pass_bitmaps_.end()) {
+ DCHECK(it->second.width() >= requirements.size.width() &&
+ it->second.height() >= requirements.size.height());
return;
+ }
// The |requirements.mipmap| is only used for gpu-based rendering, so not used
// here.
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index ea0032fe854..a94b9c8f540 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -118,39 +118,9 @@ struct SurfaceAggregator::RoundedCornerInfo {
bool is_fast_rounded_corner;
};
-struct SurfaceAggregator::ChildSurfaceInfo {
- struct QuadStateInfo {
- gfx::Transform transform_to_root_target;
- gfx::Transform quad_to_target_transform;
- gfx::Rect clip_rect;
- bool is_clipped;
- };
-
- ChildSurfaceInfo(RenderPassId parent_pass_id,
- const gfx::Rect& quad_rect,
- bool stretch_content_to_fill_bounds)
- : parent_pass_id(parent_pass_id),
- quad_rect(quad_rect),
- stretch_content_to_fill_bounds(stretch_content_to_fill_bounds) {
- // In most cases there would be one or two different embeddings of a
- // surface in the render pass tree. Reserve two elements to avoid
- // unnecessary copies.
- quad_state_infos.reserve(2);
- }
-
- RenderPassId parent_pass_id;
- gfx::Rect quad_rect;
- bool stretch_content_to_fill_bounds;
- bool has_moved_pixels = false;
- std::vector<QuadStateInfo> quad_state_infos;
-};
-
struct SurfaceAggregator::RenderPassMapEntry {
- RenderPassMapEntry(RenderPass* render_pass,
- bool has_pixel_moving_backdrop_filter)
- : render_pass(render_pass),
- damage_rect(render_pass->output_rect),
- has_pixel_moving_backdrop_filter(has_pixel_moving_backdrop_filter) {}
+ explicit RenderPassMapEntry(RenderPass* render_pass)
+ : render_pass(render_pass) {}
// Make this move-only.
RenderPassMapEntry(RenderPassMapEntry&&) = default;
@@ -161,12 +131,8 @@ struct SurfaceAggregator::RenderPassMapEntry {
RenderPass* render_pass;
// Damage rect of the render pass in its own content space.
gfx::Rect damage_rect;
- bool has_pixel_moving_backdrop_filter;
bool is_visited = false;
- // If the render pass contains any surfaces in its quad list, either from
- // SurfaceDrawQuads or from render passes referenced by RPDQs.
- bool contains_surfaces = false;
};
SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
@@ -198,18 +164,16 @@ SurfaceAggregator::GenerateRenderPassMap(const RenderPassList& render_pass_list,
// This data is created once and typically small or empty. Collect all items
// and pass to a flat_map to sort once.
std::vector<std::pair<RenderPassId, RenderPassMapEntry>> render_pass_data;
+ render_pass_data.reserve(render_pass_list.size());
for (const auto& render_pass : render_pass_list) {
- bool has_pixel_moving_backdrop_filter =
- render_pass->backdrop_filters.HasFilterThatMovesPixels();
- if (has_pixel_moving_backdrop_filter) {
+ if (render_pass->backdrop_filters.HasFilterThatMovesPixels()) {
DCHECK_NE(render_pass.get(), root_pass_in_root_surface)
<< "The root render pass on the root surface can not have backdrop "
"affecting filters";
}
- render_pass_data.emplace_back(
- std::piecewise_construct, std::forward_as_tuple(render_pass->id),
- std::forward_as_tuple(render_pass.get(),
- has_pixel_moving_backdrop_filter));
+ render_pass_data.emplace_back(std::piecewise_construct,
+ std::forward_as_tuple(render_pass->id),
+ std::forward_as_tuple(render_pass.get()));
}
return base::flat_map<RenderPassId, RenderPassMapEntry>(
std::move(render_pass_data));
@@ -308,15 +272,25 @@ gfx::Rect SurfaceAggregator::CalculateOccludingSurfaceDamageRect(
// Transform the quad to the parent root target space
// Note: this quad is on the child root render pass.
- gfx::Transform transform(parent_quad_to_root_target_transform,
- quad->shared_quad_state->quad_to_target_transform);
- gfx::Rect surface_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect);
+ gfx::Rect quad_in_root_target_space;
+ if (quad->shared_quad_state->is_clipped) {
+ gfx::Rect quad_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->visible_rect);
+ quad_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
+ quad_in_root_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ parent_quad_to_root_target_transform, quad_in_target_space);
+
+ } else {
+ gfx::Transform transform(parent_quad_to_root_target_transform,
+ quad->shared_quad_state->quad_to_target_transform);
+ quad_in_root_target_space =
+ cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect);
+ }
// damage_rects_union_of_surfaces_on_top_ is already in the parent root target
// space.
gfx::Rect occluding_damage_rect = damage_rects_union_of_surfaces_on_top_;
- occluding_damage_rect.Intersect(surface_in_root_target_space);
+ occluding_damage_rect.Intersect(quad_in_root_target_space);
return occluding_damage_rect;
}
@@ -560,6 +534,12 @@ void SurfaceAggregator::EmitSurfaceContent(
CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back()) &&
source_sqs->de_jelly_delta_y == 0;
+ if (frame.metadata.delegated_ink_metadata) {
+ TransformAndStoreDelegatedInkMetadata(
+ gfx::Transform(dest_pass->transform_to_root_target, combined_transform),
+ frame.metadata.delegated_ink_metadata.get());
+ }
+
gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage(
surface, render_pass_list, combined_transform, dest_pass,
@@ -702,14 +682,23 @@ void SurfaceAggregator::EmitSurfaceContent(
// We can't produce content outside of |quad_rect|, so clip the visible
// rect if necessary.
quad_visible_rect.Intersect(quad_rect);
-
- auto* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
RenderPassId remapped_pass_id = RemapPassId(last_pass.id, surface_id);
- quad->SetNew(shared_quad_state, quad_rect, quad_visible_rect,
- remapped_pass_id, 0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(), gfx::PointF(), tex_coord_rect,
- /*force_anti_aliasing_off=*/false,
- /* backdrop_filter_quality*/ 1.0f);
+ if (quad_visible_rect.IsEmpty()) {
+ dest_pass_list_->erase(
+ std::remove_if(
+ dest_pass_list_->begin(), dest_pass_list_->end(),
+ [&remapped_pass_id](const std::unique_ptr<RenderPass>& pass) {
+ return pass->id == remapped_pass_id;
+ }),
+ dest_pass_list_->end());
+ } else {
+ auto* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ quad->SetNew(shared_quad_state, quad_rect, quad_visible_rect,
+ remapped_pass_id, 0, gfx::RectF(), gfx::Size(),
+ gfx::Vector2dF(), gfx::PointF(), tex_coord_rect,
+ /*force_anti_aliasing_off=*/false,
+ /* backdrop_filter_quality*/ 1.0f);
+ }
}
referenced_surfaces_.erase(surface_id);
@@ -1144,6 +1133,13 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
const gfx::Transform surface_transform =
IsRootSurface(surface) ? root_surface_transform_ : gfx::Transform();
+ if (frame.metadata.delegated_ink_metadata) {
+ TransformAndStoreDelegatedInkMetadata(
+ gfx::Transform(source_pass_list.back()->transform_to_root_target,
+ surface_transform),
+ frame.metadata.delegated_ink_metadata.get());
+ }
+
gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage(
surface, source_pass_list, surface_transform,
@@ -1235,125 +1231,52 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
}
}
-void SurfaceAggregator::FindChildSurfaces(
- SurfaceId surface_id,
+gfx::Rect SurfaceAggregator::PrewalkRenderPass(
+ RenderPassId render_pass_id,
+ const Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
- RenderPassMapEntry* current_pass_entry,
+ bool will_draw,
const gfx::Transform& transform_to_root_target,
- base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
- bool* has_backdrop_cache_flags_to_update) {
- if (current_pass_entry->is_visited) {
- // This means that this render pass is an ancestor of itself. This is not
- // supported. Stop processing the render pass again.
- return;
+ PrewalkResult* result) {
+ auto it = render_pass_map->find(render_pass_id);
+ DCHECK(it != render_pass_map->end());
+ RenderPassMapEntry& render_pass_entry = it->second;
+ if (render_pass_entry.is_visited) {
+ // This render pass is an ancestor of itself (not supported) or has been
+ // processed.
+ return render_pass_entry.damage_rect;
}
- base::AutoReset<bool> reset_is_visited(&current_pass_entry->is_visited, true);
- RenderPass* render_pass = current_pass_entry->render_pass;
- if (current_pass_entry->has_pixel_moving_backdrop_filter) {
+ render_pass_entry.is_visited = true;
+ const RenderPass& render_pass = *render_pass_entry.render_pass;
+
+ if (render_pass.backdrop_filters.HasFilterThatMovesPixels()) {
has_pixel_moving_backdrop_filter_ = true;
// If the render pass has a backdrop filter that moves pixels, its entire
// bounds, with proper transform applied, may be added to the damage
// rect if it intersects.
pixel_moving_backdrop_filters_rects->push_back(
cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
- render_pass->output_rect));
+ render_pass.output_rect));
}
- RenderPassId remapped_pass_id = RemapPassId(render_pass->id, surface_id);
- bool has_pixel_moving_filter =
- render_pass->filters.HasFilterThatMovesPixels();
+
+ RenderPassId remapped_pass_id =
+ RemapPassId(render_pass.id, surface->surface_id());
+ // |moved_pixel_passes_| stores all the render passes affected by filters
+ // that move pixels, so |has_pixel_moving_filter| should be set to true either
+ // if the current render pass has pixel_moving_filter(s) or if it is inside an
+ // ancestor render pass that has pixel_moving_filter(s).
+ bool has_pixel_moving_filter = render_pass.filters.HasFilterThatMovesPixels();
if (has_pixel_moving_filter)
moved_pixel_passes_.insert(remapped_pass_id);
bool in_moved_pixel_pass =
has_pixel_moving_filter ||
base::Contains(moved_pixel_passes_, remapped_pass_id);
- for (auto* quad : render_pass->quad_list) {
- if (quad->material == DrawQuad::Material::kSurfaceContent) {
- // A child surface has been found. Add necessary info from this surface to
- // the set of child surfaces that can be used to update damage rect for
- // the parent surface. If this child surface has been visited previously,
- // we only need to update |has_moved_pixels| and add the transform
- // corresponding to this visit; rest of the info would remain the same.
- const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
- auto it = child_surfaces->find(surface_quad->surface_range);
- if (it == child_surfaces->end()) {
- auto insert_pair = child_surfaces->emplace(
- std::piecewise_construct,
- std::forward_as_tuple(surface_quad->surface_range),
- std::forward_as_tuple(
- remapped_pass_id, surface_quad->rect,
- surface_quad->stretch_content_to_fill_bounds));
- DCHECK(insert_pair.second);
- it = insert_pair.first;
- }
- auto& child_surface_info = it->second;
- if (in_moved_pixel_pass)
- child_surface_info.has_moved_pixels = true;
- child_surface_info.quad_state_infos.push_back(
- {transform_to_root_target,
- surface_quad->shared_quad_state->quad_to_target_transform,
- surface_quad->shared_quad_state->clip_rect,
- surface_quad->shared_quad_state->is_clipped});
- current_pass_entry->contains_surfaces = true;
- } else if (quad->material == DrawQuad::Material::kRenderPass) {
- // A child render pass has been found. Find its child surfaces
- // recursively.
- const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
- *has_backdrop_cache_flags_to_update |=
- render_pass_quad->can_use_backdrop_filter_cache;
- RenderPassId child_pass_id = render_pass_quad->render_pass_id;
- RenderPassId remapped_child_pass_id =
- RemapPassId(child_pass_id, surface_id);
- if (in_moved_pixel_pass)
- moved_pixel_passes_.insert(remapped_child_pass_id);
- auto child_pass_it = render_pass_map->find(child_pass_id);
- DCHECK(child_pass_it != render_pass_map->end());
- RenderPassMapEntry& child_pass_entry = child_pass_it->second;
- // TODO(crbug/1011042): Here, we used to set |in_moved_pixel_pass| to true
- // if the child render pass has a pixel-moving backdrop filter. This
- // behavior was added in r687426 to fix another problem, but caused a huge
- // performance issue in some cases that enabled background blur, by
- // expanding the damage rect unnecessarily to the entire screen
- // (crbug/1008740). This is removed now, but a proper fix for the
- // pixel-moving backdrop filter should be implemented.
- render_pass_dependencies_[remapped_pass_id].insert(
- remapped_child_pass_id);
- FindChildSurfaces(
- surface_id, render_pass_map, &child_pass_entry,
- gfx::Transform(
- transform_to_root_target,
- render_pass_quad->shared_quad_state->quad_to_target_transform),
- child_surfaces, pixel_moving_backdrop_filters_rects,
- has_backdrop_cache_flags_to_update);
- current_pass_entry->contains_surfaces |=
- child_pass_entry.contains_surfaces;
- }
- }
-}
-gfx::Rect
-SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- RenderPassId id,
- PrewalkResult* result,
- base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map) {
- auto render_pass_it = render_pass_map->find(id);
- DCHECK(render_pass_it != render_pass_map->end());
- RenderPassMapEntry& render_pass_entry = render_pass_it->second;
-
- // If there's no surface embedded in the render pass, return an empty rect.
- if (!render_pass_entry.contains_surfaces)
- return gfx::Rect();
-
- if (render_pass_entry.is_visited) {
- // This render pass is an ancestor of itself (not supported) or has been
- // processed.
- return render_pass_entry.damage_rect;
- }
- render_pass_entry.is_visited = true;
+ const CompositorFrame& frame = surface->GetActiveFrame();
+ gfx::Rect full_damage = frame.render_pass_list.back()->output_rect;
- const RenderPass& render_pass = *render_pass_entry.render_pass;
gfx::Rect damage_rect;
-
// Iterate through the quad list back-to-front and accumulate damage from
// all quads (only SurfaceDrawQuads and RenderPassDrawQuads can have damage
// at this point). |damage_rect| has damage from all quads below the current
@@ -1362,36 +1285,50 @@ SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
for (QuadList::ConstReverseIterator it = render_pass.quad_list.rbegin();
it != render_pass.quad_list.rend(); ++it) {
const DrawQuad* quad = *it;
+ gfx::Rect quad_damage_rect;
if (quad->material == DrawQuad::Material::kSurfaceContent) {
const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
- Surface* surface =
+ Surface* child_surface =
manager_->GetLatestInFlightSurface(surface_quad->surface_range);
- auto it = result->damage_on_surfaces.end();
- if (surface)
- it = result->damage_on_surfaces.find(surface->surface_id());
- if (it != result->damage_on_surfaces.end()) {
- gfx::Rect surface_damage_rect = it->second;
+ // If the primary surface is not available then we assume the damage is
+ // the full size of the SurfaceDrawQuad because we might need to introduce
+ // gutter.
+ if (!child_surface ||
+ child_surface->surface_id() != surface_quad->surface_range.end()) {
+ quad_damage_rect = quad->rect;
+ }
+
+ if (child_surface) {
+ gfx::Rect child_rect;
+ auto it = result->damage_on_surfaces.find(child_surface->surface_id());
+ if (it != result->damage_on_surfaces.end()) {
+ // the surface damage has been accummulated previously
+ child_rect = it->second;
+ } else {
+ // first encounter of the surface
+ child_rect = PrewalkSurface(child_surface, in_moved_pixel_pass,
+ remapped_pass_id, will_draw, result);
+ }
+
if (surface_quad->stretch_content_to_fill_bounds) {
- if (surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
- 0) {
+ if (!child_surface->size_in_pixels().IsEmpty()) {
float y_scale = static_cast<float>(surface_quad->rect.height()) /
- surface->size_in_pixels().height();
+ child_surface->size_in_pixels().height();
float x_scale = static_cast<float>(surface_quad->rect.width()) /
- surface->size_in_pixels().width();
- surface_damage_rect = gfx::ScaleToEnclosingRect(surface_damage_rect,
- x_scale, y_scale);
+ child_surface->size_in_pixels().width();
+ child_rect =
+ gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale);
}
}
- gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
- quad->shared_quad_state->quad_to_target_transform,
- surface_damage_rect);
- damage_rect.Union(rect_in_target_space);
- } else {
- // The damage info was not found for the (probably invalid) surface,
- // take the whole quad rect as damaged.
- gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
- quad->shared_quad_state->quad_to_target_transform, quad->rect);
- damage_rect.Union(rect_in_target_space);
+ quad_damage_rect.Union(child_rect);
+ }
+
+ if (quad_damage_rect.IsEmpty())
+ continue;
+
+ if (in_moved_pixel_pass) {
+ damage_rect = full_damage;
+ continue;
}
} else if (quad->material == DrawQuad::Material::kRenderPass) {
auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
@@ -1406,28 +1343,42 @@ SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
render_pass_quad->can_use_backdrop_filter_cache = false;
}
- gfx::Rect render_pass_damage_rect =
- UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- render_pass_quad->render_pass_id, result, render_pass_map);
+ RenderPassId child_pass_id = render_pass_quad->render_pass_id;
+ RenderPassId remapped_child_pass_id =
+ RemapPassId(child_pass_id, surface->surface_id());
+ if (in_moved_pixel_pass)
+ moved_pixel_passes_.insert(remapped_child_pass_id);
- gfx::Rect rect = cc::MathUtil::MapEnclosingClippedRect(
- render_pass_quad->shared_quad_state->quad_to_target_transform,
- render_pass_damage_rect);
- damage_rect.Union(rect);
+ render_pass_dependencies_[remapped_pass_id].insert(
+ remapped_child_pass_id);
+ quad_damage_rect = PrewalkRenderPass(
+ child_pass_id, surface, render_pass_map, will_draw,
+ gfx::Transform(
+ transform_to_root_target,
+ render_pass_quad->shared_quad_state->quad_to_target_transform),
+ pixel_moving_backdrop_filters_rects, result);
+
+ } else {
+ continue;
}
+ // Convert the quad damage rect into its target space and clip it
+ // if needed.
+ gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad_damage_rect);
+ if (quad->shared_quad_state->is_clipped) {
+ rect_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
+ }
+ damage_rect.Union(rect_in_target_space);
}
render_pass_entry.damage_rect = damage_rect;
return damage_rect;
}
-// Walk the Surface tree from surface_id. Validate the resources of the current
-// surface and its descendants, check if there are any copy requests, and
-// return the combined damage rect.
-gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
- bool in_moved_pixel_surface,
- int parent_pass_id,
- bool will_draw,
- PrewalkResult* result) {
+gfx::Rect SurfaceAggregator::PrewalkSurface(Surface* surface,
+ bool in_moved_pixel_surface,
+ int parent_pass_id,
+ bool will_draw,
+ PrewalkResult* result) {
if (referenced_surfaces_.count(surface->surface_id()))
return gfx::Rect();
@@ -1470,17 +1421,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry> render_pass_map =
GenerateRenderPassMap(frame.render_pass_list, IsRootSurface(surface));
- auto root_pass_it = render_pass_map.find(frame.render_pass_list.back()->id);
- DCHECK(root_pass_it != render_pass_map.end());
- RenderPassMapEntry& root_pass_entry = root_pass_it->second;
- base::flat_map<SurfaceRange, ChildSurfaceInfo> child_surfaces;
- std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
- bool has_backdrop_cache_flags_to_update = false;
- FindChildSurfaces(surface->surface_id(), &render_pass_map, &root_pass_entry,
- root_pass_transform, &child_surfaces,
- &pixel_moving_backdrop_filters_rects,
- &has_backdrop_cache_flags_to_update);
-
std::vector<ResourceId> referenced_resources;
referenced_resources.reserve(frame.resource_list.size());
@@ -1518,82 +1458,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
// Avoid infinite recursion by adding current surface to
// |referenced_surfaces_|.
referenced_surfaces_.insert(surface->surface_id());
- for (const auto& child_surface_info_pair : child_surfaces) {
- auto& child_surface_range = child_surface_info_pair.first;
- auto& child_surface_info = child_surface_info_pair.second;
- // TODO(fsamuel): Consider caching this value somewhere so that
- // HandleSurfaceQuad doesn't need to call it again.
- Surface* child_surface =
- manager_->GetLatestInFlightSurface(child_surface_range);
-
- // If the primary surface is not available then we assume the damage is
- // the full size of the SurfaceDrawQuad because we might need to introduce
- // gutter.
- gfx::Rect child_surface_damage;
- if (!child_surface ||
- child_surface->surface_id() != child_surface_range.end()) {
- child_surface_damage = child_surface_info.quad_rect;
- }
-
- if (child_surface) {
- if (child_surface_info.stretch_content_to_fill_bounds) {
- // Scale up the damage_quad generated by the child_surface to fit
- // the containing quad_rect.
- gfx::Rect child_rect =
- PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
- child_surface_info.parent_pass_id, will_draw, result);
- if (child_surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
- 0) {
- float y_scale =
- static_cast<float>(child_surface_info.quad_rect.height()) /
- child_surface->size_in_pixels().height();
- float x_scale =
- static_cast<float>(child_surface_info.quad_rect.width()) /
- child_surface->size_in_pixels().width();
- child_surface_damage.Union(
- gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale));
- }
- } else {
- child_surface_damage.Union(
- PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
- child_surface_info.parent_pass_id, will_draw, result));
- }
- }
-
- if (child_surface_damage.IsEmpty())
- continue;
-
- if (child_surface_info.has_moved_pixels) {
- // Areas outside the rect hit by target_to_surface_transform may be
- // modified if there is a filter that moves pixels.
- damage_rect = full_damage;
- continue;
- }
-
- // Add the child surface damage rect to the parent surface damage rect. The
- // child surface damage rect is first transformed to the parent surface
- // coordinate space. There would be multiple transforms for a child surface
- // if it is embedded multiple times which means its damage rect should be
- // added multiple times.
- for (const auto& quad_state_info : child_surface_info.quad_state_infos) {
- gfx::Transform target_to_surface_transform(
- quad_state_info.transform_to_root_target,
- quad_state_info.quad_to_target_transform);
-
- gfx::Rect child_surface_damage_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(target_to_surface_transform,
- child_surface_damage);
- if (quad_state_info.is_clipped) {
- gfx::Rect clip_rect_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(
- quad_state_info.transform_to_root_target,
- quad_state_info.clip_rect);
- child_surface_damage_in_root_target_space.Intersect(
- clip_rect_in_root_target_space);
- }
- damage_rect.Union(child_surface_damage_in_root_target_space);
- }
- }
+ std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
+ const gfx::Rect surface_root_damage = PrewalkRenderPass(
+ frame.render_pass_list.back()->id, surface, &render_pass_map, will_draw,
+ root_pass_transform, &pixel_moving_backdrop_filters_rects, result);
+ damage_rect.Union(cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ root_pass_transform, surface_root_damage));
if (!damage_rect.IsEmpty()) {
// The following call can cause one or more copy requests to be added to the
@@ -1635,7 +1505,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
result->undrawn_surfaces.insert(surface_id);
Surface* undrawn_surface = manager_->GetSurfaceForId(surface_id);
if (undrawn_surface)
- PrewalkTree(undrawn_surface, false, 0, false /* will_draw */, result);
+ PrewalkSurface(undrawn_surface, false, 0, /*will_draw=*/false, result);
}
}
@@ -1673,11 +1543,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
std::forward_as_tuple(damage_rect));
DCHECK(emplace_result.second);
- if (has_backdrop_cache_flags_to_update) {
- UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- frame.render_pass_list.back()->id, result, &render_pass_map);
- }
-
return damage_rect;
}
@@ -1763,6 +1628,7 @@ CompositorFrame SurfaceAggregator::Aggregate(
const SurfaceId& surface_id,
base::TimeTicks expected_display_time,
gfx::OverlayTransform display_transform,
+ const gfx::Rect& target_damage,
int64_t display_trace_id) {
DCHECK(!expected_display_time.is_null());
@@ -1810,8 +1676,14 @@ CompositorFrame SurfaceAggregator::Aggregate(
new_surfaces_.clear();
DCHECK(referenced_surfaces_.empty());
PrewalkResult prewalk_result;
- root_damage_rect_ =
- PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result);
+ gfx::Rect surfaces_damage_rect =
+ PrewalkSurface(surface, false, 0, /*will_draw=*/true, &prewalk_result);
+
+ root_damage_rect_ = surfaces_damage_rect;
+ // |root_damage_rect_| is used to restrict aggregating quads only if they
+ // intersect this area.
+ root_damage_rect_.Union(target_damage);
+
root_content_color_usage_ = prewalk_result.content_color_usage;
if (prewalk_result.frame_sinks_changed)
@@ -1827,6 +1699,15 @@ CompositorFrame SurfaceAggregator::Aggregate(
CopyPasses(root_surface_frame, surface);
referenced_surfaces_.erase(surface_id);
+ // The root render pass damage might have been expanded by target_damage (the
+ // area that might need to be recomposited on the target surface). We restrict
+ // the damage_rect of the root render pass to the one caused by the source
+ // surfaces.
+ // The damage on the root render pass should not include the expanded area
+ // since Renderer and OverlayProcessor expect the non expanded damage.
+ if (!RenderPassNeedsFullDamage(dest_pass_list_->back().get()))
+ dest_pass_list_->back()->damage_rect.Intersect(surfaces_damage_rect);
+
// Now that we've handled our main surface aggregation, apply de-jelly effect
// if enabled.
if (de_jelly_enabled_)
@@ -1875,6 +1756,8 @@ CompositorFrame SurfaceAggregator::Aggregate(
}
}
+ frame.metadata.delegated_ink_metadata = std::move(delegated_ink_metadata_);
+
if (frame_annotator_)
frame_annotator_->AnnotateAggregatedFrame(&frame);
@@ -1941,6 +1824,43 @@ bool SurfaceAggregator::IsRootSurface(const Surface* surface) const {
return surface->surface_id() == root_surface_id_;
}
+// Transform the point and presentation area of the metadata to be in the root
+// target space. They need to be in the root target space because they will
+// eventually be drawn directly onto the buffer just before being swapped onto
+// the screen, so root target space is required so that they are positioned
+// correctly. After transforming, they are stored in the
+// |delegated_ink_metadata_| member in order to be placed on the final
+// aggregated frame, after which the member is then cleared.
+void SurfaceAggregator::TransformAndStoreDelegatedInkMetadata(
+ const gfx::Transform& parent_quad_to_root_target_transform,
+ DelegatedInkMetadata* metadata) {
+ if (delegated_ink_metadata_) {
+ // This member could already be populated in two scenarios:
+ // 1. The delegated ink metadata was committed to a frame's metadata that
+ // wasn't ultimately used to produce a frame, but is now being used.
+ // 2. There are two or more ink strokes requesting a delegated ink trail
+ // simultaneously.
+ // In both cases, we want to default to using a "last write wins" strategy
+ // to determine the metadata to put on the final aggregated frame. This
+ // avoids potential issues of using stale ink metadata in the first scenario
+ // by always using the newest one. For the second scenario, it would be a
+ // very niche use case to have more than one at a time, so the explainer
+ // specifies using last write wins to decide.
+ base::TimeTicks stored_time = delegated_ink_metadata_->timestamp();
+ base::TimeTicks new_time = metadata->timestamp();
+ if (new_time < stored_time)
+ return;
+ }
+
+ gfx::PointF point(metadata->point());
+ gfx::RectF area(metadata->presentation_area());
+ parent_quad_to_root_target_transform.TransformPoint(&point);
+ parent_quad_to_root_target_transform.TransformRect(&area);
+ delegated_ink_metadata_ = std::make_unique<DelegatedInkMetadata>(
+ point, metadata->diameter(), metadata->color(), metadata->timestamp(),
+ area);
+}
+
void SurfaceAggregator::HandleDeJelly(Surface* surface) {
TRACE_EVENT0("viz", "SurfaceAggregator::HandleDeJelly");
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index 6da752f8739..9f3c9a41a79 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -8,11 +8,14 @@
#include <memory>
#include <string>
#include <unordered_map>
+#include <utility>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/common/resources/transferable_resource.h"
@@ -50,9 +53,14 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
bool needs_surface_occluding_damage_rect);
~SurfaceAggregator();
+ // |target_damage| represents an area on the output surface that might have
+ // been invalidated. It can be used in cases where we still want to support
+ // partial damage but the target surface might need contents outside the
+ // damage rect of the root surface.
CompositorFrame Aggregate(const SurfaceId& surface_id,
base::TimeTicks expected_display_time,
gfx::OverlayTransform display_transform,
+ const gfx::Rect& target_damage = gfx::Rect(),
int64_t display_trace_id = -1);
void ReleaseResources(const SurfaceId& surface_id);
const SurfaceIndexMap& previous_contained_surfaces() const {
@@ -181,61 +189,42 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const gfx::Rect& occluding_damage_rect,
bool occluding_damage_rect_valid);
- // Helper function that uses backtracking on the render pass tree of a surface
- // to find all surfaces embedded in it. If a surface is embedded multiple
- // times (due to use of a MirrorLayer), it will be reachable via multiple
- // paths from the root render pass. For each such a path the appropriate
- // transform is calculated.
- // - |surface_id| specifies the surface to find all child surfaces of.
- // - |render_pass_map| is a pre-computed map from render pass id to some info
- // about the render pass, including the render pass itself and whether it
- // has pixel moving backdrop filter.
- // - |current_pass_entry| is the info about the current render pass to
- // process.
+ // Recursively walks through the render pass and updates the
+ // |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
+ // The function returns the damage rect of the render pass in its own content
+ // space.
+ // - |render_pass_id| specifies the id of the render pass.
+ // - |surface| is the surface containing the render pass.
+ // - |render_pass_map| is a map that contains all render passes and their
+ // entry data.
+ // - |will_draw| indicates that the surface can be aggregated into the final
+ // frame and might be drawn (based on damage/occlusion/etc.) if it is set
+ // to true. Or the surface isn't in the aggregated frame and is only
+ // needed for CopyOutputRequests if set to false.
// - |transform_to_root_target| is the accumulated transform of all render
- // passes along the way to the current render pass.
- // - |child_surfaces| is the main output of the function containing all child
- // surfaces found in the process.
- // - |pixel_moving_backdrop_filters_rect| is another output that is union of
- // bounds of render passes that have a pixel moving backdrop filter.
- // - |has_backdrop_cache_flags_to_update| indicates if any
- // RenderPassDrawQuad(s) contained in the surface have
- // |can_use_backdrop_filter_cache| flag set to true and having to be
- // updated. This is used to avoid iterating through all the render passes
- // in the surface frame when not needed (i.e. no flag needs to be
- // updated).
- // TODO(mohsen): Consider refactoring this backtracking algorithm into a
- // self-contained class.
- void FindChildSurfaces(
- SurfaceId surface_id,
+ // passes in the containing surface along the way to the current render
+ // pass.
+ // - |pixel_moving_backdrop_filters_rects| is a vector of bounds of render
+ // passes that have a pixel moving backdrop filter.
+ // - |result| is the result of a prewalk of the surface that contains the
+ // render pass.
+ gfx::Rect PrewalkRenderPass(
+ RenderPassId render_pass_id,
+ const Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
- RenderPassMapEntry* current_pass_entry,
+ bool will_draw,
const gfx::Transform& transform_to_root_target,
- base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
- bool* has_backdrop_cache_flags_to_update);
-
- // Recursively updates the |can_use_backdrop_filter_cache| flag on all
- // RenderPassDrawQuads(RPDQ) in the specified render pass. The function
- // recursively traverses any render pass referenced by a RPDQ but doesn't
- // traverse any render passes in the frame of any embedded surfaces. The
- // function returns the damage rect of the render pass in its own content
- // space.
- // - |id| specifies the render pass whose quads are to be updated
- // - |result| is the result of a prewalk of a root surface that contains the
- // render pass
- // - |render_pass_map| is a map that contains all render passes and their
- // entry data
- gfx::Rect UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- RenderPassId id,
- PrewalkResult* result,
- base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map);
-
- gfx::Rect PrewalkTree(Surface* surface,
- bool in_moved_pixel_surface,
- int parent_pass,
- bool will_draw,
- PrewalkResult* result);
+ PrewalkResult* result);
+
+ // Walk the Surface tree from |surface|. Validate the resources of the
+ // current surface and its descendants, check if there are any copy requests,
+ // and return the combined damage rect.
+ gfx::Rect PrewalkSurface(Surface* surface,
+ bool in_moved_pixel_surface,
+ int parent_pass,
+ bool will_draw,
+ PrewalkResult* result);
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
void CopyPasses(const CompositorFrame& frame, Surface* surface);
void AddColorConversionPass();
@@ -276,6 +265,15 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
static void UnrefResources(base::WeakPtr<SurfaceClient> surface_client,
const std::vector<ReturnedResource>& resources);
+ // This method transforms the delegated ink metadata to be in the root target
+ // space, so that it can eventually be drawn onto the back buffer in the
+ // correct position. It should only ever be called when a frame contains
+ // delegated ink metadata, in which case this function will transform it and
+ // then store it in the |delegated_ink_metadata_| member.
+ void TransformAndStoreDelegatedInkMetadata(
+ const gfx::Transform& parent_quad_to_root_target_transform,
+ DelegatedInkMetadata* metadata);
+
// De-Jelly Effect:
// HandleDeJelly applies a de-jelly transform to quads in the root render
// pass.
@@ -436,6 +434,13 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// production on Windows only (does not interact with jelly).
bool last_frame_had_color_conversion_pass_ = false;
+ // The metadata used for drawing a delegated ink trail on the end of a normal
+ // ink stroke. It needs to be transformed to root coordinates and then put on
+ // the final aggregated frame. This is only populated during aggregation when
+ // a surface contains delegated ink metadata on its frame, and it is cleared
+ // after it is placed on the final aggregated frame during aggregation.
+ std::unique_ptr<DelegatedInkMetadata> delegated_ink_metadata_;
+
base::WeakPtrFactory<SurfaceAggregator> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator);
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index 0a3f1ae681d..085c6cd27cb 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -7,6 +7,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
+#include <map>
#include <set>
#include <utility>
#include <vector>
@@ -132,10 +134,11 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
testing::Test::TearDown();
}
- CompositorFrame AggregateFrame(const SurfaceId& surface_id) {
+ CompositorFrame AggregateFrame(const SurfaceId& surface_id,
+ gfx::Rect target_damage = gfx::Rect()) {
return aggregator_.Aggregate(
surface_id, GetNextDisplayTimeAndIncrement(),
- gfx::OVERLAY_TRANSFORM_NONE /* display_transform */);
+ /*display_transform=*/gfx::OVERLAY_TRANSFORM_NONE, target_damage);
}
struct Quad {
@@ -4399,6 +4402,133 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
}
}
+TEST_F(SurfaceAggregatorPartialSwapTest, ExpandByTargetDamage) {
+ ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ constexpr float device_scale_factor = 1.0f;
+
+ // The child surface has one quad.
+ {
+ int child_pass_id = 1;
+ std::vector<Quad> child_quads1 = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {
+ Pass(child_quads1, child_pass_id, gfx::Rect(5, 5))};
+
+ RenderPassList child_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&child_pass_list, child_passes, &referenced_surfaces);
+
+ SubmitPassListAsFrame(child_sink_.get(), child_local_surface_id,
+ &child_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ {
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(SurfaceSize()), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+ // No damage, this is the first frame submitted, so all quads should be
+ // produced.
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // Damage rect for first aggregation should contain entire root surface.
+ EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list.back()->damage_rect);
+ EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
+
+ // Create a root surface with a smaller damage rect.
+ // This time the damage should be smaller.
+ {
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(SurfaceSize()), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+
+ auto* root_pass = root_pass_list[0].get();
+ root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ {
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // No quads inside the damage
+ EXPECT_EQ(gfx::Rect(10, 10, 2, 2),
+ aggregated_pass_list.back()->damage_rect);
+ EXPECT_EQ(0u, aggregated_pass_list.back()->quad_list.size());
+ }
+
+ // This pass has damage that does not intersect the quad in the child
+ // surface.
+ {
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
+ SK_ColorWHITE, gfx::Rect(SurfaceSize()), false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+
+ auto* root_pass = root_pass_list[0].get();
+ root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ // The target surface invalidates one pixel in the top left, the quad in the
+ // child surface should be added even if it's not causing damage nor in the
+ // root render pass damage.
+ {
+ gfx::Rect target_damage(0, 0, 1, 1);
+ CompositorFrame aggregated_frame =
+ AggregateFrame(root_surface_id, target_damage);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // The damage rect of the root render pass should not be changed.
+ EXPECT_EQ(gfx::Rect(10, 10, 2, 2),
+ aggregated_pass_list.back()->damage_rect);
+ // We expect one quad
+ ASSERT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
+ }
+}
+
class SurfaceAggregatorWithResourcesTest : public testing::Test,
public DisplayTimeSource {
public:
@@ -5667,6 +5797,41 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
EXPECT_EQ(gfx::Rect(60, 0, 30, 40),
video_sqs->occluding_damage_rect.value());
}
+ // Frame #4 - Has occluding damage and clipping of the video quad is on
+ {
+ CompositorFrame child_surface_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_surface_frame.render_pass_list, child_surface_passes,
+ &child_surface_frame.metadata.referenced_surfaces);
+
+ auto* render_pass = child_surface_frame.render_pass_list[0].get();
+ auto* surface_quad_sqs = render_pass->shared_quad_state_list.front();
+ surface_quad_sqs->is_clipped = true;
+ surface_quad_sqs->clip_rect = gfx::Rect(20, 0, 60, 80);
+
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_surface_frame));
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
+ // The video quad (10, 0, 80, 80) unions the solid quad on top (60, 0, 40,
+ // 40)
+ EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect);
+
+ const SharedQuadState* video_sqs =
+ output_root_pass->quad_list.back()->shared_quad_state;
+ // The solid quad on top (60, 0, 40, 40) intersects the clipped video quad
+ // (26, 0, 48, 64)
+ EXPECT_EQ(gfx::Rect(60, 0, 14, 40),
+ video_sqs->occluding_damage_rect.value());
+ }
}
// Tests that quads outside the damage rect are not ignored for cached render
@@ -5833,7 +5998,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DisplayTransformDamageCallback) {
std::vector<Quad> root_quads = {Quad::SurfaceQuad(
SurfaceRange(primary_child_surface_id), SK_ColorWHITE, surface_quad_rect,
/*stretch_content_to_fill_bounds=*/true)};
- std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ constexpr gfx::Size surface_size(60, 100);
+ std::vector<Pass> root_passes = {Pass(root_quads, surface_size)};
MockAggregatedDamageCallback aggregated_damage_callback;
root_sink_->SetAggregatedDamageCallbackForTesting(
@@ -5844,15 +6011,14 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DisplayTransformDamageCallback) {
SubmitCompositorFrame(root_sink_.get(), root_passes, root_local_surface_id_,
0.5f);
- EXPECT_CALL(
- aggregated_damage_callback,
- OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
- gfx::Rect(SurfaceSize()), next_display_time()));
+ EXPECT_CALL(aggregated_damage_callback,
+ OnAggregatedDamage(root_local_surface_id_, surface_size,
+ gfx::Rect(surface_size), next_display_time()));
- gfx::Rect transformed_rect(SurfaceSize().height(), SurfaceSize().width());
CompositorFrame frame =
aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement(),
gfx::OVERLAY_TRANSFORM_ROTATE_90);
+ gfx::Rect transformed_rect(surface_size.height(), surface_size.width());
EXPECT_EQ(frame.render_pass_list.back()->output_rect, transformed_rect);
EXPECT_EQ(frame.render_pass_list.back()->damage_rect, transformed_rect);
}
@@ -6434,6 +6600,63 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AllowMerge) {
}
}
+// Check that if a non-merged surface is invisible, its entire render pass is
+// skipped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SkipInvisibleSurface) {
+ // Child surface.
+ gfx::Rect child_rect(5, 5);
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, child_rect)};
+ // Offset child output rect so it's outside the root visible rect.
+ gfx::Rect output_rect(SurfaceSize());
+ output_rect.Offset(output_rect.width(), output_rect.height());
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, output_rect)};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+ }
+
+ gfx::Rect root_rect(SurfaceSize());
+
+ auto pass = RenderPass::Create();
+ pass->SetNew(1, root_rect, root_rect, gfx::Transform());
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->opacity = 1.f;
+
+ // Disallow merge.
+ auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+ surface_quad->SetAll(sqs, child_rect, child_rect,
+ /*needs_blending=*/false,
+ SurfaceRange(base::nullopt, child_surface_id),
+ SK_ColorWHITE,
+ /*stretch_content_to_fill_bounds=*/false,
+ /*is_reflection=*/false,
+ /*allow_merge=*/false);
+
+ CompositorFrame frame =
+ CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+ // Merging not allowed, but child rect should be dropped.
+ EXPECT_EQ(1u, aggregated_frame.render_pass_list.size());
+}
+
// Verify that a SurfaceDrawQuad's root RenderPass has correct texture
// parameters if being drawn via RPDQ.
TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassDoesNotFillSurface) {
@@ -6691,5 +6914,562 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
hit_test_region_index);
}
+void ExpectDelegatedInkMetadataIsEqual(const DelegatedInkMetadata& lhs,
+ const DelegatedInkMetadata& rhs) {
+ EXPECT_FLOAT_EQ(lhs.point().y(), rhs.point().y());
+ EXPECT_FLOAT_EQ(lhs.point().x(), rhs.point().x());
+ EXPECT_EQ(lhs.diameter(), rhs.diameter());
+ EXPECT_EQ(lhs.color(), rhs.color());
+ EXPECT_EQ(lhs.timestamp(), rhs.timestamp());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().y(), rhs.presentation_area().y());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().x(), rhs.presentation_area().x());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().width(),
+ rhs.presentation_area().width());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().height(),
+ rhs.presentation_area().height());
+}
+
+// Basic test to confirm that ink metadata on a child surface will be
+// transformed by the parent.
+TEST_F(SurfaceAggregatorValidSurfaceTest, DelegatedInkMetadataTest) {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
+ base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200));
+ child_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm that transforms are aggregated as the tree is walked and correctly
+// applied to the ink metadata.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ TransformDelegatedInkMetadataTallTree) {
+ auto greatgrand_child_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+ std::vector<Quad> greatgrandchild_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> greatgrandchild_passes = {
+ Pass(greatgrandchild_quads, 1, gfx::Size(100, 100))};
+
+ DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
+ base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200));
+ CompositorFrame greatgrandchild_frame = MakeEmptyCompositorFrame();
+ greatgrandchild_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&greatgrandchild_frame.render_pass_list, greatgrandchild_passes,
+ &greatgrandchild_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator greatgrandchild_allocator;
+ greatgrandchild_allocator.GenerateId();
+ LocalSurfaceId greatgrandchild_local_surface_id =
+ greatgrandchild_allocator.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id();
+ SurfaceId great_grandchild_surface_id(
+ greatgrand_child_support->frame_sink_id(),
+ greatgrandchild_local_surface_id);
+ greatgrand_child_support->SubmitCompositorFrame(
+ greatgrandchild_local_surface_id, std::move(greatgrandchild_frame));
+
+ auto grand_child_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ std::vector<Quad> grandchild_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, great_grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(7, 7), /*stretch_content_to_fill_bounds=*/false)};
+ std::vector<Pass> grandchild_passes = {
+ Pass(grandchild_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame grandchild_frame = MakeEmptyCompositorFrame();
+
+ AddPasses(&grandchild_frame.render_pass_list, grandchild_passes,
+ &grandchild_frame.metadata.referenced_surfaces);
+
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(37, 82);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ ParentLocalSurfaceIdAllocator grandchild_allocator;
+ grandchild_allocator.GenerateId();
+ LocalSurfaceId grandchild_local_surface_id =
+ grandchild_allocator.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id();
+ SurfaceId grandchild_surface_id(grand_child_support->frame_sink_id(),
+ grandchild_local_surface_id);
+ grand_child_support->SubmitCompositorFrame(grandchild_local_surface_id,
+ std::move(grandchild_frame));
+
+ std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(7, 7), /*stretch_content_to_fill_bounds=*/false)};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(36, 15);
+
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(0.7, 0.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm the metadata is transformed correctly and makes it to the aggregated
+// frame when there are multiple children.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ DelegatedInkMetadataMultipleChildren) {
+ auto child_2_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ auto child_3_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+
+ std::vector<Quad> child_1_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_1_passes = {
+ Pass(child_1_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_1_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_1_frame.render_pass_list, child_1_passes,
+ &child_1_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_1_allocator;
+ child_1_allocator.GenerateId();
+ LocalSurfaceId child_1_local_surface_id =
+ child_1_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_1_surface_id(child_sink_->frame_sink_id(),
+ child_1_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_1_local_surface_id,
+ std::move(child_1_frame));
+
+ std::vector<Quad> child_2_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+ std::vector<Pass> child_2_passes = {
+ Pass(child_2_quads, 1, gfx::Size(100, 100))};
+
+ DelegatedInkMetadata metadata = DelegatedInkMetadata(
+ gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
+ gfx::RectF(50, 50, 300, 300));
+ CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
+ child_2_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_2_frame.render_pass_list, child_2_passes,
+ &child_2_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_2_allocator;
+ child_2_allocator.GenerateId();
+ LocalSurfaceId child_2_local_surface_id =
+ child_2_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_2_surface_id(child_2_support->frame_sink_id(),
+ child_2_local_surface_id);
+ child_2_support->SubmitCompositorFrame(child_2_local_surface_id,
+ std::move(child_2_frame));
+
+ std::vector<Quad> child_3_quads = {
+ Quad::SolidColorQuad(SK_ColorCYAN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_3_passes = {
+ Pass(child_3_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_3_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_3_frame.render_pass_list, child_3_passes,
+ &child_3_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_3_allocator;
+ child_3_allocator.GenerateId();
+ LocalSurfaceId child_3_local_surface_id =
+ child_3_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_3_surface_id(child_3_support->frame_sink_id(),
+ child_3_local_surface_id);
+ child_3_support->SubmitCompositorFrame(child_3_local_surface_id,
+ std::move(child_3_frame));
+
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_1_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_2_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_3_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(9, 87);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Scale(0.7, 0.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Translate(70, 240);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(2)
+ ->quad_to_target_transform.Scale(2.7, 0.2);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm the the metadata with the most recent timestamp is used when
+// multiple children have delegated ink metadata.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ MultipleChildrenHaveDelegatedInkMetadata) {
+ auto child_2_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ auto child_3_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+
+ std::vector<Quad> child_1_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_1_passes = {
+ Pass(child_1_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_1_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_1_frame.render_pass_list, child_1_passes,
+ &child_1_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_1_allocator;
+ child_1_allocator.GenerateId();
+ LocalSurfaceId child_1_local_surface_id =
+ child_1_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_1_surface_id(child_sink_->frame_sink_id(),
+ child_1_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_1_local_surface_id,
+ std::move(child_1_frame));
+
+ std::vector<Quad> child_2_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+ std::vector<Pass> child_2_passes = {
+ Pass(child_2_quads, 1, gfx::Size(100, 100))};
+
+ // Making both metadatas here so that the one with a later timestamp can be
+ // on child 2. This will cause the test to fail if we don't default to using
+ // the metadata with the later timestamp. Specifically setting the
+ // later_metadata timestamp to be 50 microseconds later than Now() to avoid
+ // issues with both metadatas sometimes having the same time in Release.
+ DelegatedInkMetadata early_metadata = DelegatedInkMetadata(
+ gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
+ gfx::RectF(50, 50, 300, 300));
+ DelegatedInkMetadata later_metadata = DelegatedInkMetadata(
+ gfx::PointF(92, 35), 0.08, SK_ColorYELLOW,
+ base::TimeTicks::Now() + base::TimeDelta::FromMicroseconds(50),
+ gfx::RectF(35, 55, 128, 256));
+
+ CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
+ child_2_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(later_metadata);
+ AddPasses(&child_2_frame.render_pass_list, child_2_passes,
+ &child_2_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_2_allocator;
+ child_2_allocator.GenerateId();
+ LocalSurfaceId child_2_local_surface_id =
+ child_2_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_2_surface_id(child_2_support->frame_sink_id(),
+ child_2_local_surface_id);
+ child_2_support->SubmitCompositorFrame(child_2_local_surface_id,
+ std::move(child_2_frame));
+
+ std::vector<Quad> child_3_quads = {
+ Quad::SolidColorQuad(SK_ColorCYAN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_3_passes = {
+ Pass(child_3_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_3_frame = MakeEmptyCompositorFrame();
+ child_3_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(early_metadata);
+ AddPasses(&child_3_frame.render_pass_list, child_3_passes,
+ &child_3_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_3_allocator;
+ child_3_allocator.GenerateId();
+ LocalSurfaceId child_3_local_surface_id =
+ child_3_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_3_surface_id(child_3_support->frame_sink_id(),
+ child_3_local_surface_id);
+ child_3_support->SubmitCompositorFrame(child_3_local_surface_id,
+ std::move(child_3_frame));
+
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_1_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_2_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_3_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(9, 87);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Scale(1.4, 1.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Translate(214, 144);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(2)
+ ->quad_to_target_transform.Scale(2.7, 0.2);
+
+ // Two surfaces have delegated ink metadata on them, and when this happens
+ // on the metadata with the most recent timestamp should be used. Take this
+ // metadata and transform it to what should be expected.
+ gfx::PointF pt = later_metadata.point();
+ gfx::RectF area = later_metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ DelegatedInkMetadata expected_metadata = DelegatedInkMetadata(
+ pt, later_metadata.diameter(), later_metadata.color(),
+ later_metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), expected_metadata);
+}
+
+// Confirm that delegated ink metadata on an undrawn surface is not on the
+// aggregated surface unless the undrawn surface contains a CopyOutputRequest.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ DelegatedInkMetadataOnUndrawnSurface) {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ DelegatedInkMetadata metadata(gfx::PointF(34, 89), 1.597, SK_ColorBLUE,
+ base::TimeTicks::Now(),
+ gfx::RectF(2.3, 3.2, 177, 212));
+ child_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ // Do not put the child surface in a SurfaceDrawQuad so that it remains
+ // undrawn.
+ std::vector<Quad> root_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ root_frame.metadata.referenced_surfaces.emplace_back(
+ SurfaceRange(base::nullopt, child_surface_id));
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ EXPECT_FALSE(aggregated_frame.metadata.delegated_ink_metadata);
+
+ // Now add a CopyOutputRequest on the child surface, so that the delegated
+ // ink metadata does get populated on the aggregated frame.
+ auto copy_request = CopyOutputRequest::CreateStubForTesting();
+ child_sink_->RequestCopyOfOutput(child_local_surface_id,
+ std::move(copy_request));
+
+ aggregated_frame = AggregateFrame(root_surface_id);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
} // namespace
} // namespace viz