[lacros] Add clip rect support for delegated compositing over Wayland
Forward clip_rect data from lacros viz to ash chrome. Due to hardware
limitations, UVs need to line up on pixel boundaries for textures to
be promoted to overlays. Geometric clipping doesn't always satisfy
this, so this clip needs to be preserved for delegated quads that we
want to end up as hardware overlays.
This feature is disabled by default, and is enabled by the visual
debugger flag "candidate.enable.clip_rect".
Overlay clip rect design note:
https://docs.google.com/document/d/10udDdyzVVnpixgQU-K3u51z9SESOpGvcpfFQIJLzC4A
Subsurface transformation design doc:
https://docs.google.com/document/d/1rfwkx0u281iMCS45KAl3j9BcdUc3HshBpbb8aDS0my8
Bug: 1348751
Change-Id: I0bc63d32834b076abbe6493ad962906cd0c5b034
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3860121
Commit-Queue: River Gilhuly <rivr@chromium.org>
Reviewed-by: Peter McNeeley <petermcneeley@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Reviewed-by: Kramer Ge <fangzhoug@chromium.org>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1046539}
diff --git a/components/exo/sub_surface.cc b/components/exo/sub_surface.cc
index 0d6be46..1c765cf 100644
--- a/components/exo/sub_surface.cc
+++ b/components/exo/sub_surface.cc
@@ -49,6 +49,16 @@
parent_->SetSubSurfacePosition(surface_, position);
}
+void SubSurface::SetClipRect(const absl::optional<gfx::RectF>& clip_rect) {
+ TRACE_EVENT1("exo", "SubSurface::SetClipRect", "clip_rect",
+ (clip_rect ? clip_rect->ToString() : "nullopt"));
+
+ if (!parent_ || !surface_)
+ return;
+
+ surface_->SetClipRect(clip_rect);
+}
+
void SubSurface::PlaceAbove(Surface* reference) {
TRACE_EVENT1("exo", "SubSurface::PlaceAbove", "reference",
reference->AsTracedValue());
diff --git a/components/exo/sub_surface.h b/components/exo/sub_surface.h
index 7b67ff3..ce12bbe 100644
--- a/components/exo/sub_surface.h
+++ b/components/exo/sub_surface.h
@@ -10,9 +10,11 @@
#include "base/observer_list.h"
#include "components/exo/surface_delegate.h"
#include "components/exo/surface_observer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/class_property.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h"
namespace base {
@@ -43,6 +45,9 @@
// of the parent surface coordinate system.
void SetPosition(const gfx::PointF& position);
+ // This schedules a clip rect to be applied when drawing this sub-surface.
+ void SetClipRect(const absl::optional<gfx::RectF>& clip_rect);
+
// This removes sub-surface from the stack, and puts it back just above the
// reference surface, changing the z-order of the sub-surfaces. The reference
// surface must be one of the sibling surfaces, or the parent surface.
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index f07a5d8..e5e3ca9 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -542,6 +542,16 @@
pending_state_.overlay_priority_hint = hint;
}
+void Surface::SetClipRect(const absl::optional<gfx::RectF>& clip_rect) {
+ TRACE_EVENT1("exo", "Surface::SetClipRect", "clip_rect",
+ (clip_rect ? clip_rect->ToString() : "nullopt"));
+
+ if (pending_state_.clip_rect == clip_rect) {
+ return;
+ }
+ pending_state_.clip_rect = clip_rect;
+}
+
void Surface::SetBackgroundColor(absl::optional<SkColor4f> background_color) {
TRACE_EVENT0("exo", "Surface::SetBackgroundColor");
pending_state_.basic_state.background_color = background_color;
@@ -799,6 +809,7 @@
}
cached_state_.rounded_corners_bounds = pending_state_.rounded_corners_bounds;
cached_state_.overlay_priority_hint = pending_state_.overlay_priority_hint;
+ cached_state_.clip_rect = pending_state_.clip_rect;
cached_state_.acquire_fence = std::move(pending_state_.acquire_fence);
cached_state_.per_commit_explicit_release_callback_ =
std::move(pending_state_.per_commit_explicit_release_callback_);
@@ -939,6 +950,7 @@
}
state_.rounded_corners_bounds = cached_state_.rounded_corners_bounds;
state_.overlay_priority_hint = cached_state_.overlay_priority_hint;
+ state_.clip_rect = cached_state_.clip_rect;
state_.acquire_fence = std::move(cached_state_.acquire_fence);
state_.per_commit_explicit_release_callback_ =
std::move(cached_state_.per_commit_explicit_release_callback_);
@@ -1330,6 +1342,15 @@
}
}
+ absl::optional<gfx::Rect> quad_clip_rect;
+ if (state_.clip_rect) {
+ // The clip rect will later be rescaled by 1/device_scale_factor, and the
+ // enclosing rect used. Take the enclosed rect here to mitigate error.
+ gfx::RectF clip_rect_px(*state_.clip_rect);
+ clip_rect_px.Scale(device_scale_factor);
+ quad_clip_rect = gfx::ToEnclosedRect(clip_rect_px);
+ }
+
state_.damage.Clear();
gfx::PointF scale(content_size_.width(), content_size_.height());
@@ -1413,8 +1434,8 @@
viz::SharedQuadState* quad_state =
render_pass->CreateAndAppendSharedQuadState();
quad_state->SetAll(/*quad_layer_rect=*/quad_to_target_transform, quad_rect,
- /*visible_quad_layer_rect=*/quad_rect,
- /*mask_filter_info=*/msk, /*clip_rect=*/absl::nullopt,
+ /*visible_layer_rect=*/quad_rect,
+ /*filter_info=*/msk, /*clip=*/quad_clip_rect,
/*contents_opaque=*/are_contents_opaque,
/*opacity=*/state_.basic_state.alpha,
/*blend_mode=*/SkBlendMode::kSrcOver,
diff --git a/components/exo/surface.h b/components/exo/surface.h
index fd7fe2ad..e3e0e7e 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -181,6 +181,9 @@
void SetRoundedCorners(const gfx::RRectF& rounded_corners_bounds);
void SetOverlayPriorityHint(OverlayPriority hint);
+ // Sets the surface's clip rectangle.
+ void SetClipRect(const absl::optional<gfx::RectF>& clip_rect);
+
// Sets the background color that shall be associated with the next buffer
// commit.
void SetBackgroundColor(absl::optional<SkColor4f> background_color);
@@ -532,6 +535,10 @@
// The hint for overlay prioritization
// Persisted between commits.
OverlayPriority overlay_priority_hint = OverlayPriority::REGULAR;
+ // The clip rect for this surface, in the parent's coordinate space. This
+ // should only be set for subsurfaces.
+ // Persisted between commits.
+ absl::optional<gfx::RectF> clip_rect;
};
friend class subtle::PropertyHelper;
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 8134863ff..fa386d4a 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -1567,5 +1567,59 @@
EXPECT_EQ(buffer_release_count, 1);
}
+TEST_P(SurfaceTest, SubsurfaceClipRect) {
+ gfx::Size buffer_size(256, 256);
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ surface->Attach(buffer.get());
+
+ gfx::Size child_buffer_size(64, 128);
+ auto child_buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
+ auto child_surface = std::make_unique<Surface>();
+ auto sub_surface =
+ std::make_unique<SubSurface>(child_surface.get(), surface.get());
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface initially has no clip.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ ASSERT_EQ(2u, frame.render_pass_list.back()->quad_list.size());
+ const auto& quad_list = frame.render_pass_list[0]->quad_list;
+ EXPECT_EQ(absl::nullopt, quad_list.front()->shared_quad_state->clip_rect);
+ }
+
+ int clip_size_px = 10;
+ float clip_size_dip = clip_size_px / device_scale_factor();
+ absl::optional<gfx::RectF> clip_rect =
+ gfx::RectF(clip_size_dip, clip_size_dip, clip_size_dip, clip_size_dip);
+ sub_surface->SetClipRect(clip_rect);
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface has a clip applied, and it is converted to px in the
+ // compositor frame.
+ absl::optional<gfx::Rect> clip_rect_px =
+ gfx::Rect(clip_size_px, clip_size_px, clip_size_px, clip_size_px);
+
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ ASSERT_EQ(2u, frame.render_pass_list.back()->quad_list.size());
+ const auto& quad_list = frame.render_pass_list[0]->quad_list;
+ EXPECT_EQ(clip_rect_px, quad_list.front()->shared_quad_state->clip_rect);
+ }
+}
+
} // namespace
} // namespace exo
diff --git a/components/exo/wayland/protocol/surface-augmenter.xml b/components/exo/wayland/protocol/surface-augmenter.xml
index c79d9fa4..f7cf0bf 100644
--- a/components/exo/wayland/protocol/surface-augmenter.xml
+++ b/components/exo/wayland/protocol/surface-augmenter.xml
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="surface_augmenter" version="3">
+ <interface name="surface_augmenter" version="4">
<description summary="surface composition delegation">
The global interface exposing surface delegated composition
capabilities is used to instantiate an interface extension for a
@@ -172,13 +172,13 @@
</request>
</interface>
- <interface name="augmented_sub_surface" version="1">
- <description summary="delegate composition of a wl_subsurface">
+ <interface name="augmented_sub_surface" version="4">
+ <description summary="delegate composition of a wl_subsurface">
An additional interface to a wl_subsurface object, which allows the
client to specify the delegated composition of the surface
contents.
</description>
- <request name="destroy" type="destructor">
+ <request name="destroy" type="destructor">
<description summary="remove delegated composition of the surface">
The associated wl_surface's augmenter is removed.
The change is applied on the next wl_surface.commit.
@@ -207,6 +207,23 @@
<arg name="x" type="fixed" summary="x coordinate in the parent surface"/>
<arg name="y" type="fixed" summary="y coordinate in the parent surface"/>
</request>
+ <request name="set_clip_rect" since="4">
+ <description summary="sets a subsurface clip rect with subpixel accuracy">
+ This schedules a clip rect to be applied when drawing this sub-surface.
+ The clip will be placed with its origin (top left corner pixel) at the
+ location x, y of the parent surface coordinate system. The coordinates are not
+ restricted to the parent surface area. Negative x and y values are allowed.
+
+ If all of x, y, width and height are -1.0, the clip rect is unset instead.
+
+ Initially, surfaces have no clip set.
+ This state is double-buffered, and is applied on the next wl_surface.commit.
+ </description>
+ <arg name="x" type="fixed" summary="x coordinate in the parent surface"/>
+ <arg name="y" type="fixed" summary="y coordinate in the parent surface"/>
+ <arg name="width" type="fixed" summary="width of the clip rect"/>
+ <arg name="height" type="fixed" summary="height of the clip rect"/>
+ </request>
</interface>
</protocol>
diff --git a/components/exo/wayland/surface_augmenter.cc b/components/exo/wayland/surface_augmenter.cc
index 2e141f9..54b016e 100644
--- a/components/exo/wayland/surface_augmenter.cc
+++ b/components/exo/wayland/surface_augmenter.cc
@@ -180,6 +180,15 @@
sub_surface_->SetPosition(gfx::PointF(x, y));
}
+ void SetClipRect(float x, float y, float width, float height) {
+ absl::optional<gfx::RectF> clip_rect;
+ if (x >= 0 && y >= 0 && width >= 0 && height >= 0) {
+ clip_rect = gfx::RectF(x, y, width, height);
+ }
+ // TODO(rivr): Should we send a protocol error if there are invalid values?
+ sub_surface_->SetClipRect(clip_rect);
+ }
+
// SurfaceObserver:
void OnSubSurfaceDestroying(SubSurface* sub_surface) override {
sub_surface->RemoveSubSurfaceObserver(this);
@@ -202,9 +211,21 @@
wl_fixed_to_double(x), wl_fixed_to_double(y));
}
+void augmented_sub_surface_set_clip_rect(wl_client* client,
+ wl_resource* resource,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ wl_fixed_t width,
+ wl_fixed_t height) {
+ GetUserDataAs<AugmentedSubSurface>(resource)->SetClipRect(
+ wl_fixed_to_double(x), wl_fixed_to_double(y), wl_fixed_to_double(width),
+ wl_fixed_to_double(height));
+}
+
const struct augmented_sub_surface_interface
- augmented_sub_surface_implementation = {augmented_sub_surface_destroy,
- augmented_sub_surface_set_position};
+ augmented_sub_surface_implementation = {
+ augmented_sub_surface_destroy, augmented_sub_surface_set_position,
+ augmented_sub_surface_set_clip_rect};
////////////////////////////////////////////////////////////////////////////////
// wl_buffer_interface:
diff --git a/components/exo/wayland/surface_augmenter.h b/components/exo/wayland/surface_augmenter.h
index addf487..bf64d9fc 100644
--- a/components/exo/wayland/surface_augmenter.h
+++ b/components/exo/wayland/surface_augmenter.h
@@ -12,7 +12,7 @@
namespace exo {
namespace wayland {
-constexpr uint32_t kSurfaceAugmenterVersion = 3;
+constexpr uint32_t kSurfaceAugmenterVersion = 4;
void bind_surface_augmenter(wl_client* client,
void* data,
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc
index 6a465019..6917bd4 100644
--- a/components/viz/service/display/overlay_candidate_factory.cc
+++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -173,13 +173,15 @@
const SurfaceDamageRectList* surface_damage_rect_list,
const SkM44* output_color_matrix,
const gfx::RectF primary_rect,
- bool is_delegated_context)
+ bool is_delegated_context,
+ bool supports_clip_rect)
: render_pass_(render_pass),
resource_provider_(resource_provider),
surface_damage_rect_list_(surface_damage_rect_list),
output_color_matrix_(output_color_matrix),
primary_rect_(primary_rect),
- is_delegated_context_(is_delegated_context) {
+ is_delegated_context_(is_delegated_context),
+ supports_clip_rect_(supports_clip_rect) {
// TODO(crbug.com/1323002): Replace this set with a simple ordered linear
// search when this bug is resolved.
base::flat_set<size_t> indices_with_quad_damage;
@@ -339,25 +341,31 @@
resource_provider_->GetSurfaceId(resource_id).frame_sink_id();
}
- // Delegated compositing does not yet support |clip_rect| so it is applied
- // here to the |display_rect| and |uv_rect| directly.
-
if (is_delegated_context_) {
- if (candidate.clip_rect.has_value())
- OverlayCandidate::ApplyClip(candidate, gfx::RectF(*candidate.clip_rect));
+ // The delegate might not support specifying |clip_rect| so if not, apply it
+ // to the |display_rect| and |uv_rect| directly.
+ if (!supports_clip_rect_) {
+ if (candidate.clip_rect.has_value())
+ OverlayCandidate::ApplyClip(candidate,
+ gfx::RectF(*candidate.clip_rect));
- if (quad->visible_rect != quad->rect) {
- auto visible_rect = gfx::RectF(quad->visible_rect);
- transform.TransformRect(&visible_rect);
- OverlayCandidate::ApplyClip(candidate, gfx::RectF(visible_rect));
+ // TODO(rivr): Apply the same |visible_rect| and |display_rect| clip logic
+ // when delegating |clip_rect|.
+ if (quad->visible_rect != quad->rect) {
+ auto visible_rect = gfx::RectF(quad->visible_rect);
+ transform.TransformRect(&visible_rect);
+ OverlayCandidate::ApplyClip(candidate, gfx::RectF(visible_rect));
+ }
+ // TODO(https://crbug.com/1300552) : Tile quads can overlay other quads
+ // and the window by one pixel. Exo does not yet clip these quads so we
+ // need to clip here with the |primary_rect|.
+ OverlayCandidate::ApplyClip(candidate, primary_rect_);
+
+ if (candidate.display_rect.IsEmpty())
+ return CandidateStatus::kFailVisible;
+
+ candidate.clip_rect = absl::nullopt;
}
- // TODO(https://crbug.com/1300552) : Tile quads can overlay other quads and
- // the window by one pixel. Exo does not yet clip these quads so we need to
- // clip here with the |primary_rect|.
- OverlayCandidate::ApplyClip(candidate, primary_rect_);
-
- if (candidate.display_rect.IsEmpty())
- return CandidateStatus::kFailVisible;
}
candidate.tracking_id = base::Hash(&track_data, sizeof(track_data));
diff --git a/components/viz/service/display/overlay_candidate_factory.h b/components/viz/service/display/overlay_candidate_factory.h
index f9dfb0e3..2120834 100644
--- a/components/viz/service/display/overlay_candidate_factory.h
+++ b/components/viz/service/display/overlay_candidate_factory.h
@@ -51,7 +51,8 @@
const SurfaceDamageRectList* surface_damage_rect_list,
const SkM44* output_color_matrix,
const gfx::RectF primary_rect,
- bool is_delegated_context = false);
+ bool is_delegated_context = false,
+ bool supports_clip_rect = false);
OverlayCandidateFactory(const OverlayCandidateFactory&) = delete;
OverlayCandidateFactory& operator=(const OverlayCandidateFactory&) = delete;
@@ -120,7 +121,8 @@
raw_ptr<const SurfaceDamageRectList> surface_damage_rect_list_;
raw_ptr<const SkM44> output_color_matrix_;
const gfx::RectF primary_rect_;
- bool is_delegated_context_;
+ const bool is_delegated_context_;
+ const bool supports_clip_rect_;
// The union of all surface damages that are not specifically assigned to a
// draw quad.
diff --git a/components/viz/service/display/overlay_processor_delegated.cc b/components/viz/service/display/overlay_processor_delegated.cc
index 3255a652..92c182e 100644
--- a/components/viz/service/display/overlay_processor_delegated.cc
+++ b/components/viz/service/display/overlay_processor_delegated.cc
@@ -96,6 +96,9 @@
ui::OzonePlatform::GetInstance()
->GetOverlayManager()
->SetContextDelegated();
+ supports_clip_rect_ = ui::OzonePlatform::GetInstance()
+ ->GetPlatformRuntimeProperties()
+ .supports_clip_rect;
}
OverlayProcessorDelegated::~OverlayProcessorDelegated() = default;
@@ -111,6 +114,9 @@
DBG_FLAG_FBOOL("delegated.disable.delegation", disable_delegation)
+// TODO(rivr): Enable clip_rect delegation by default.
+DBG_FLAG_FBOOL("candidate.enable.clip_rect", enable_clip_rect)
+
bool OverlayProcessorDelegated::AttemptWithStrategies(
const SkM44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap&
@@ -150,7 +156,7 @@
OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
render_pass, resource_provider, surface_damage_rect_list,
&output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane),
- is_delegated_context);
+ is_delegated_context, supports_clip_rect_ && enable_clip_rect());
std::vector<QuadList::Iterator> candidate_quads;
int num_quads_skipped = 0;
diff --git a/components/viz/service/display/overlay_processor_delegated.h b/components/viz/service/display/overlay_processor_delegated.h
index 6efdfe7..9dce973 100644
--- a/components/viz/service/display/overlay_processor_delegated.h
+++ b/components/viz/service/display/overlay_processor_delegated.h
@@ -107,6 +107,7 @@
std::vector<gfx::Rect>* content_bounds);
DelegationStatus delegated_status_ = DelegationStatus::kCompositedOther;
+ bool supports_clip_rect_ = false;
};
} // namespace viz
diff --git a/components/viz/service/display_embedder/output_presenter_gl.cc b/components/viz/service/display_embedder/output_presenter_gl.cc
index dc555d2..57dee3e7 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -444,7 +444,8 @@
overlay_plane_candidate.rounded_corners,
overlay_plane_candidate.color_space,
overlay_plane_candidate.hdr_metadata, overlay_plane_candidate.color,
- overlay_plane_candidate.is_solid_color));
+ overlay_plane_candidate.is_solid_color,
+ overlay_plane_candidate.clip_rect));
}
#elif BUILDFLAG(IS_APPLE)
gl_surface_->ScheduleCALayer(ui::CARendererLayerParams(
diff --git a/ui/gfx/overlay_plane_data.cc b/ui/gfx/overlay_plane_data.cc
index bfd3d19..34410bfd 100644
--- a/ui/gfx/overlay_plane_data.cc
+++ b/ui/gfx/overlay_plane_data.cc
@@ -21,7 +21,8 @@
const gfx::ColorSpace& color_space,
const absl::optional<HDRMetadata>& hdr_metadata,
absl::optional<SkColor4f> color,
- bool is_solid_color)
+ bool is_solid_color,
+ absl::optional<Rect> clip_rect)
: z_order(z_order),
plane_transform(plane_transform),
display_bounds(display_bounds),
@@ -34,7 +35,8 @@
color_space(color_space),
hdr_metadata(hdr_metadata),
color(color),
- is_solid_color(is_solid_color) {}
+ is_solid_color(is_solid_color),
+ clip_rect(clip_rect) {}
OverlayPlaneData::~OverlayPlaneData() = default;
diff --git a/ui/gfx/overlay_plane_data.h b/ui/gfx/overlay_plane_data.h
index 99488b0..b7fa2df 100644
--- a/ui/gfx/overlay_plane_data.h
+++ b/ui/gfx/overlay_plane_data.h
@@ -32,7 +32,8 @@
const gfx::ColorSpace& color_space,
const absl::optional<HDRMetadata>& hdr_metadata,
absl::optional<SkColor4f> color = absl::nullopt,
- bool is_solid_color = false);
+ bool is_solid_color = false,
+ absl::optional<Rect> clip_rect = absl::nullopt);
~OverlayPlaneData();
OverlayPlaneData(const OverlayPlaneData& other);
@@ -80,6 +81,9 @@
// Set if this is a solid color quad.
bool is_solid_color;
+
+ // Optional clip rect for this overlay.
+ absl::optional<gfx::Rect> clip_rect;
};
} // namespace gfx
diff --git a/ui/ozone/platform/wayland/common/wayland_overlay_config.cc b/ui/ozone/platform/wayland/common/wayland_overlay_config.cc
index c6c649a0..279fc868 100644
--- a/ui/ozone/platform/wayland/common/wayland_overlay_config.cc
+++ b/ui/ozone/platform/wayland/common/wayland_overlay_config.cc
@@ -32,7 +32,8 @@
rounded_clip_bounds(data.rounded_corners),
// Solid color quads are created as wl_buffers. Though, some overlays may
// have background data passed.
- background_color(data.is_solid_color ? absl::nullopt : data.color) {}
+ background_color(data.is_solid_color ? absl::nullopt : data.color),
+ clip_rect(data.clip_rect) {}
WaylandOverlayConfig& WaylandOverlayConfig::operator=(
WaylandOverlayConfig&& other) = default;
diff --git a/ui/ozone/platform/wayland/common/wayland_overlay_config.h b/ui/ozone/platform/wayland/common/wayland_overlay_config.h
index c6704f5..8f17447 100644
--- a/ui/ozone/platform/wayland/common/wayland_overlay_config.h
+++ b/ui/ozone/platform/wayland/common/wayland_overlay_config.h
@@ -84,6 +84,9 @@
// Optional: background color of this overlay plane.
absl::optional<SkColor4f> background_color;
+
+ // Optional: clip rect for this overlay.
+ absl::optional<gfx::Rect> clip_rect;
};
} // namespace wl
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 0be711f..3ed77fd 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -93,6 +93,8 @@
supports_surface_background_color_ =
supported_surface_augmentor_version >=
AUGMENTED_SURFACE_SET_BACKGROUND_COLOR_SINCE_VERSION;
+ supports_clip_rect_ = supported_surface_augmentor_version >=
+ AUGMENTED_SUB_SURFACE_SET_CLIP_RECT_SINCE_VERSION;
BindHostInterface(std::move(remote_host));
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
index 61e40ff..c08726b 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
@@ -151,6 +151,7 @@
bool supports_surface_background_color() const {
return supports_surface_background_color_;
}
+ bool supports_clip_rect() const { return supports_clip_rect_; }
// Adds a WaylandBufferManagerGpu binding.
void AddBindingWaylandBufferManagerGpu(
@@ -259,6 +260,8 @@
// export wl_buffers backed by dmabuf.
bool supports_dmabuf_ = true;
+ bool supports_clip_rect_ = false;
+
mojo::ReceiverSet<ozone::mojom::WaylandBufferManagerGpu> receiver_set_;
// A pointer to a WaylandBufferManagerHost object, which always lives on a
diff --git a/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc b/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc
index 995f0c23a..609697e 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc
@@ -100,6 +100,14 @@
return false;
}
+ // If clipping isn't supported, reject candidates with a clip rect, unless
+ // that clip wouldn't have any effect.
+ if (!manager_gpu_->supports_clip_rect() && candidate.clip_rect &&
+ !candidate.clip_rect->Contains(
+ gfx::ToNearestRect(candidate.display_rect))) {
+ return false;
+ }
+
if (is_delegated_context_) {
// Support for subpixel accurate position could be checked in ctor, but the
// WaylandBufferManagerGpu is not initialized when |this| is created. Thus,
@@ -114,11 +122,6 @@
if (!gfx::IsNearestRectWithinDistance(candidate.display_rect, 0.01f))
return false;
- if (candidate.clip_rect && !candidate.clip_rect->Contains(
- gfx::ToNearestRect(candidate.display_rect))) {
- return false;
- }
-
return true;
}
diff --git a/ui/ozone/platform/wayland/host/surface_augmenter.cc b/ui/ozone/platform/wayland/host/surface_augmenter.cc
index e04604d..801545a 100644
--- a/ui/ozone/platform/wayland/host/surface_augmenter.cc
+++ b/ui/ozone/platform/wayland/host/surface_augmenter.cc
@@ -15,7 +15,7 @@
namespace {
constexpr uint32_t kMinVersion = 1;
-constexpr uint32_t kMaxVersion = 3;
+constexpr uint32_t kMaxVersion = 4;
}
// static
@@ -55,6 +55,11 @@
SURFACE_AUGMENTER_GET_AUGMENTED_SUBSURFACE_SINCE_VERSION;
}
+bool SurfaceAugmenter::SupportsClipRect() const {
+ return GetSurfaceAugmentorVersion() >=
+ AUGMENTED_SUB_SURFACE_SET_CLIP_RECT_SINCE_VERSION;
+}
+
uint32_t SurfaceAugmenter::GetSurfaceAugmentorVersion() const {
return surface_augmenter_get_version(augmenter_.get());
}
diff --git a/ui/ozone/platform/wayland/host/surface_augmenter.h b/ui/ozone/platform/wayland/host/surface_augmenter.h
index 2c1502ad..3363942 100644
--- a/ui/ozone/platform/wayland/host/surface_augmenter.h
+++ b/ui/ozone/platform/wayland/host/surface_augmenter.h
@@ -35,6 +35,7 @@
~SurfaceAugmenter();
bool SupportsSubpixelAccuratePosition() const;
+ bool SupportsClipRect() const;
uint32_t GetSurfaceAugmentorVersion() const;
diff --git a/ui/ozone/platform/wayland/host/wayland_frame_manager.cc b/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
index b9aecf9..5809c61 100644
--- a/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_frame_manager.cc
@@ -236,7 +236,7 @@
}
} else {
subsurface->ConfigureAndShowSurface(
- config.bounds_rect, root_config.bounds_rect,
+ config.bounds_rect, root_config.bounds_rect, config.clip_rect,
root_config.surface_scale_factor, nullptr, reference_above);
ApplySurfaceConfigure(frame.get(), surface, config, true);
// A fatal error happened. Must stop the playback and terminate the gpu
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index 5f57317..e41f18c 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -29,6 +29,8 @@
return wl::TranslateBoundsToParentCoordinatesF(bounds_dip, parent_bounds_dip);
}
+const wl_fixed_t kMinusOne = wl_fixed_from_int(-1);
+
} // namespace
namespace ui {
@@ -105,6 +107,7 @@
void WaylandSubsurface::ConfigureAndShowSurface(
const gfx::RectF& bounds_px,
const gfx::RectF& parent_bounds_px,
+ const absl::optional<gfx::Rect>& clip_rect_px,
float buffer_scale,
WaylandSubsurface* new_below,
WaylandSubsurface* new_above) {
@@ -134,6 +137,33 @@
}
}
+ if (augmented_subsurface_ &&
+ connection_->surface_augmenter()->SupportsClipRect()) {
+ absl::optional<gfx::RectF> clip_dip_in_parent_surface;
+ if (clip_rect_px) {
+ clip_dip_in_parent_surface = AdjustSubsurfaceBounds(
+ gfx::RectF(*clip_rect_px), parent_bounds_px,
+ connection_->surface_submission_in_pixel_coordinates()
+ ? 1.f
+ : buffer_scale);
+ }
+ if (clip_dip_in_parent_surface != clip_dip_) {
+ clip_dip_ = clip_dip_in_parent_surface;
+ if (clip_dip_) {
+ augmented_sub_surface_set_clip_rect(
+ augmented_subsurface_.get(), wl_fixed_from_double(clip_dip_->x()),
+ wl_fixed_from_double(clip_dip_->y()),
+ wl_fixed_from_double(clip_dip_->width()),
+ wl_fixed_from_double(clip_dip_->height()));
+ } else {
+ // Call set_clip_rect with all values -1 to clear the clip rect.
+ augmented_sub_surface_set_clip_rect(augmented_subsurface_.get(),
+ kMinusOne, kMinusOne, kMinusOne,
+ kMinusOne);
+ }
+ }
+ }
+
// Setup the stacking order of this subsurface.
DCHECK(!new_above || !new_below);
if (new_below && new_below != previous()) {
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.h b/ui/ozone/platform/wayland/host/wayland_subsurface.h
index e829aed..02343af 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.h
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.h
@@ -38,12 +38,15 @@
// |bounds_px|: The pixel bounds of this subsurface content in
// display::Display coordinates used by chrome.
// |parent_bounds_px|: Same as |bounds_px| but for the parent surface.
+ // |clip_rect_px|: The pixel bounds of this subsurface's clip rect in
+ // display::Display coordinates. Pass nullopt to unset the clip rect.
// |buffer_scale|: the scale factor of the next attached buffer.
// |reference_below| & |reference_above|: this subsurface is taken from the
// subsurface stack and inserted back to be immediately below/above the
// reference subsurface.
void ConfigureAndShowSurface(const gfx::RectF& bounds_px,
const gfx::RectF& parent_bounds_px,
+ const absl::optional<gfx::Rect>& clip_rect_px,
float buffer_scale,
WaylandSubsurface* reference_below,
WaylandSubsurface* reference_above);
@@ -63,6 +66,7 @@
wl::Object<wl_subsurface> subsurface_;
wl::Object<augmented_sub_surface> augmented_subsurface_;
gfx::PointF position_dip_;
+ absl::optional<gfx::RectF> clip_dip_;
const raw_ptr<WaylandConnection> connection_;
// |parent_| refers to the WaylandWindow whose wl_surface is the parent to
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index d8bfc01..4a31313 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -3335,7 +3335,7 @@
EXPECT_TRUE(mock_surface_subsurface);
wayland_subsurface->ConfigureAndShowSurface(
subsurface_bounds, gfx::RectF(0, 0, 640, 480) /*parent_bounds_px*/,
- 1.f /*buffer_scale*/, nullptr, nullptr);
+ absl::nullopt /*clip_rect_px*/, 1.f /*buffer_scale*/, nullptr, nullptr);
connection_->Flush();
Sync();
@@ -3413,8 +3413,8 @@
auto subsurfaces = RequestWaylandSubsurface(3);
for (auto* subsurface : subsurfaces) {
subsurface->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f),
- gfx::RectF(0.f, 0.f, 800.f, 600.f), 1.f,
- nullptr, nullptr);
+ gfx::RectF(0.f, 0.f, 800.f, 600.f),
+ absl::nullopt, 1.f, nullptr, nullptr);
}
connection_->Flush();
@@ -3446,15 +3446,15 @@
EXPECT_CALL(*test_subs[2], SetPosition(_, _)).Times(0);
// Stack subsurfaces[0] to be from bottom to top, and change its position.
- subsurfaces[0]->ConfigureAndShowSurface(gfx::RectF(0.f, 0.f, 10.f, 20.f),
- gfx::RectF(0.f, 0.f, 800.f, 600.f),
- 1.f, subsurfaces[2], nullptr);
- subsurfaces[1]->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f),
- gfx::RectF(0.f, 0.f, 800.f, 600.f),
- 1.f, nullptr, subsurfaces[2]);
- subsurfaces[2]->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f),
- gfx::RectF(0.f, 0.f, 800.f, 600.f),
- 1.f, nullptr, subsurfaces[0]);
+ subsurfaces[0]->ConfigureAndShowSurface(
+ gfx::RectF(0.f, 0.f, 10.f, 20.f), gfx::RectF(0.f, 0.f, 800.f, 600.f),
+ absl::nullopt, 1.f, subsurfaces[2], nullptr);
+ subsurfaces[1]->ConfigureAndShowSurface(
+ gfx::RectF(1.f, 2.f, 10.f, 20.f), gfx::RectF(0.f, 0.f, 800.f, 600.f),
+ absl::nullopt, 1.f, nullptr, subsurfaces[2]);
+ subsurfaces[2]->ConfigureAndShowSurface(
+ gfx::RectF(1.f, 2.f, 10.f, 20.f), gfx::RectF(0.f, 0.f, 800.f, 600.f),
+ absl::nullopt, 1.f, nullptr, subsurfaces[0]);
connection_->Flush();
Sync();
diff --git a/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom b/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom
index 8edc807..348b01d7 100644
--- a/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom
+++ b/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom
@@ -69,4 +69,7 @@
// Optional: background color of this overlay plane.
skia.mojom.SkColor4f? background_color;
+
+ // Optional: clip rect for this overlay.
+ gfx.mojom.Rect? clip_rect;
};
diff --git a/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc b/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc
index 63694c27..4c782a6 100644
--- a/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc
+++ b/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc
@@ -63,6 +63,8 @@
return false;
if (!data.ReadBackgroundColor(&out->background_color))
return false;
+ if (!data.ReadClipRect(&out->clip_rect))
+ return false;
return true;
}
diff --git a/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h b/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h
index a0aaf07..42dcbc30 100644
--- a/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h
+++ b/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h
@@ -81,6 +81,11 @@
return input.background_color;
}
+ static const absl::optional<gfx::Rect>& clip_rect(
+ const wl::WaylandOverlayConfig& input) {
+ return input.clip_rect;
+ }
+
static bool Read(wl::mojom::WaylandOverlayConfigDataView data,
wl::WaylandOverlayConfig* out);
};
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 48a1e205..8d61dd6 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -351,6 +351,7 @@
buffer_manager_->supports_viewporter();
properties.supports_native_pixmaps =
surface_factory_->SupportsNativePixmaps();
+ properties.supports_clip_rect = buffer_manager_->supports_clip_rect();
}
return properties;
}
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index 193224d3..e509c5b3 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -195,6 +195,10 @@
// Wayland only: determines whether BufferQueue needs a background image to
// be stacked below an AcceleratedWidget to make a widget opaque.
bool needs_background_image = false;
+
+ // Wayland only: determines whether clip rects can be delegated via the
+ // wayland protocol.
+ bool supports_clip_rect = false;
};
// Corresponds to chrome_browser_main_extra_parts.h.