1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_priority_hint.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_zcr_color_space.h"
struct wp_content_type_v1;
struct wp_fractional_scale_v1;
struct zwp_linux_buffer_release_v1;
struct zcr_blending_v1;
namespace ui {
class WaylandSyncobjAcquireTimeline;
class WaylandConnection;
class WaylandOutput;
class WaylandWindow;
class WaylandBufferHandle;
class WaylandZcrColorManagementSurface;
// Wrapper of a wl_surface, owned by a WaylandWindow or a WlSubsurface.
class WaylandSurface {
public:
using ExplicitReleaseCallback =
base::OnceCallback<void(wl_buffer*, base::ScopedFD)>;
WaylandSurface(WaylandConnection* connection, WaylandWindow* root_window);
WaylandSurface(const WaylandSurface&) = delete;
WaylandSurface& operator=(const WaylandSurface&) = delete;
~WaylandSurface();
WaylandWindow* root_window() const { return root_window_; }
overlay_prioritized_surface* overlay_priority_surface() {
return overlay_priority_surface_.get();
}
wl_surface* surface() const { return surface_.get(); }
wp_viewport* viewport() const { return viewport_.get(); }
zcr_blending_v1* blending() const { return blending_.get(); }
uint32_t buffer_id() const { return state_.buffer_id; }
float opacity() const { return state_.opacity; }
bool use_blending() const { return state_.use_blending; }
const std::vector<uint32_t>& entered_outputs() const {
return entered_outputs_;
}
// Requests an explicit release for the next commit.
void RequestExplicitRelease(ExplicitReleaseCallback callback);
// Returns an id that identifies the |wl_surface_|.
uint32_t get_surface_id() const { return surface_ ? surface_.id() : 0u; }
// Returns a gfx::AcceleratedWidget that identifies the WaylandWindow that
// this WaylandSurface belongs to.
gfx::AcceleratedWidget get_widget() const;
// Initializes the WaylandSurface and returns true iff success.
// This may return false if a wl_surface could not be created, for example.
bool Initialize();
// Unsets |root_window_|. This is intended to be used in special cases, where
// the underlying wl_surface must be kept alive with no root window associated
// (e.g: window/tab dragging sessions).
void UnsetRootWindow();
void SetRootWindow(WaylandWindow* window);
// Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
// Returns true if wl_surface.attach will be called in ApplyPendingStates().
bool AttachBuffer(WaylandBufferHandle* buffer_handle);
// Describes where the surface needs to be repainted according to
// |buffer_pending_damage_region|, which should be in buffer coordinates (px).
void UpdateBufferDamageRegion(const gfx::Rect& damage_px);
// Sets a non-null in-fence, must be combined with an AttachBuffer() and a
// Commit().
void set_acquire_fence(gfx::GpuFenceHandle acquire_fence);
// Sets an optional transformation for how the Wayland compositor interprets
// the contents of the buffer attached to this surface.
void set_buffer_transform(gfx::OverlayTransform transform) {
DCHECK(!apply_state_immediately_);
DCHECK(transform != gfx::OVERLAY_TRANSFORM_INVALID);
pending_state_.buffer_transform = transform;
return;
}
// Sets the |buffer_scale| (with respect to the scale factor used by the GPU
// process) for the next submitted buffer. This helps Wayland compositor to
// determine buffer size in dip (GPU operates in pixels. So, when buffers are
// created, their requested size is in pixels).
void set_surface_buffer_scale(float scale);
// Sets the region that is opaque on this surface in physical pixels. This is
// expected to be called whenever the region that the surface span changes or
// the opacity changes. Rects in |region_px| are specified surface-local, in
// physical pixels. If |region_px| is nullopt or empty, the opaque region is
// reset to empty.
void set_opaque_region(std::optional<std::vector<gfx::Rect>> region_px);
// Sets the input region on this surface in physical pixels.
// The input region indicates which parts of the surface accept pointer and
// touch input events. This is expected to be called from ToplevelWindow
// whenever the region that the surface span changes or window state changes
// when custom frame is used. If |region_px| is nullptr, the input region is
// reset to cover the entire wl_surface.
void set_input_region(std::optional<std::vector<gfx::Rect>> region_px);
// Set the crop uv of the attached wl_buffer.
// Unlike wp_viewport.set_source, this crops the buffer prior to
// |buffer_transform| being applied to the buffer, it will be transformed s.t.
// wp_viewport.source is called with correct params.
// See:
// https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml
// If |crop| is empty, the source rectangle is unset.
// Note this method does not send corresponding wayland requests until
// attaching the next buffer.
void set_buffer_crop(const gfx::RectF& crop) {
DCHECK(!apply_state_immediately_);
pending_state_.crop = crop == gfx::RectF{1.f, 1.f} ? gfx::RectF() : crop;
}
// Sets the opacity of the wl_surface using zcr_blending_v1_set_alpha.
// See: alpha-compositing-unstable-v1.xml
void set_opacity(const float opacity) {
DCHECK(!apply_state_immediately_);
if (blending())
pending_state_.opacity = opacity;
}
// Sets the blending equation of the wl_surface using
// zcr_blending_v1_set_blending. See: alpha-compositing-unstable-v1.xml
void set_blending(const bool use_blending) {
DCHECK(!apply_state_immediately_);
if (blending())
pending_state_.use_blending = use_blending;
}
// Set the destination size of the associated wl_surface according to
// |dest_size_px|, which should be in physical pixels.
// Note this method sends corresponding wayland requests immediately because
// it does not need a new buffer attach to take effect.
void set_viewport_destination(const gfx::SizeF& dest_size_px) {
DCHECK(!apply_state_immediately_);
pending_state_.viewport_px = dest_size_px;
}
// Sets the priority hint for the overlay that is committed via this surface.
void set_overlay_priority(gfx::OverlayPriorityHint priority_hint) {
if (overlay_priority_surface())
pending_state_.priority_hint = priority_hint;
}
// Sets whether this surface contains a video.
void set_contains_video(bool contains_video) {
pending_state_.contains_video = contains_video;
}
// Creates a wl_subsurface relating this surface and a parent surface,
// |parent|. Callers take ownership of the wl_subsurface.
wl::Object<wl_subsurface> CreateSubsurface(WaylandSurface* parent);
// When display is removed, the WaylandOutput from `entered_outputs_` should
// be removed.
void RemoveEnteredOutput(uint32_t id);
// Set surface ColorSpace
void set_color_space(gfx::ColorSpace color_space);
// Validates the |pending_state_| and generates the corresponding requests.
// Then copy |pending_states_| to |states_|.
// Returns whether or not changes require a commit to the wl_surface, or
// std::nullopt if it fails to apply the pending state.
std::optional<bool> ApplyPendingState();
// Commits the underlying wl_surface, triggers a wayland connection flush if
// |flush| is true.
void Commit(bool flush = true);
// Workaround used by GLSurfaceWayland when libgbm is not available. Causes
// SetSurfaceBufferScale() SetOpaqueRegion(), and SetInputRegion() to take
// effect immediately.
void ForceImmediateStateApplication();
// Asks the Wayland compositor to enable or disable the keyboard shortcuts
// inhibition for this surface. i.e: to receive key events even if they match
// compositor accelerators, e.g: Alt+Tab, etc.
void SetKeyboardShortcutsInhibition(bool enabled);
std::optional<float> preferred_scale_factor() const {
return preferred_scale_factor_;
}
private:
FRIEND_TEST_ALL_PREFIXES(WaylandWindowTest,
DoesNotCreateSurfaceSyncOnCommitWithoutBuffers);
FRIEND_TEST_ALL_PREFIXES(PerSurfaceScaleWaylandWindowTest,
UiScale_HandleFontScaleChange);
FRIEND_TEST_ALL_PREFIXES(PerSurfaceScaleWaylandWindowTest,
UiScale_HandleServerTriggeredBoundsChange);
FRIEND_TEST_ALL_PREFIXES(PerSurfaceScaleWaylandWindowTest,
UiScale_InitScaleAndBounds);
FRIEND_TEST_ALL_PREFIXES(PerSurfaceScaleWaylandWindowTest,
UiScale_HandlePopupGeometry);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceTest, SetExplicitSyncSuccess);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ConfigureWithExplicitSync);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitSyncNotSet_AcquireTimelineCreationFailed);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitSyncNotSet_ReleaseTimelineCreationFailed);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitSyncNotSet_InitialAcquireFenceNotSet);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitNotSyncSet_InitialAcquireFenceImportFail);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitSyncSet_SubsequentAcquireFenceNotSet);
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceExplicitSyncTest,
ExplicitSyncNotSet_SubsequentAcquireFenceImportFail);
// Holds information about each explicit synchronization buffer release.
struct ExplicitReleaseInfoLegacy {
ExplicitReleaseInfoLegacy(
wl::Object<zwp_linux_buffer_release_v1>&& linux_buffer_release,
wl_buffer* buffer,
ExplicitReleaseCallback explicit_release_callback);
~ExplicitReleaseInfoLegacy();
ExplicitReleaseInfoLegacy(const ExplicitReleaseInfoLegacy&) = delete;
ExplicitReleaseInfoLegacy& operator=(const ExplicitReleaseInfoLegacy&) =
delete;
ExplicitReleaseInfoLegacy(ExplicitReleaseInfoLegacy&&);
ExplicitReleaseInfoLegacy& operator=(ExplicitReleaseInfoLegacy&&);
wl::Object<zwp_linux_buffer_release_v1> linux_buffer_release;
// The buffer associated with this explicit release.
raw_ptr<wl_buffer, AcrossTasksDanglingUntriaged> buffer;
// The associated release callback with this request.
ExplicitReleaseCallback explicit_release_callback;
};
struct State {
State();
State(const State& other) = delete;
State& operator=(const State& other);
~State();
std::vector<gfx::Rect> damage_px;
std::vector<gfx::Rect> opaque_region_px;
std::vector<gfx::Rect> input_region_px;
// The current color space of the surface.
scoped_refptr<WaylandZcrColorSpace> color_space = nullptr;
// The acquire gpu fence to associate with the surface buffer.
gfx::GpuFenceHandle acquire_fence;
uint32_t buffer_id = 0;
// Note that this wl_buffer ptr is never cleared, even when the
// buffer_handle owning this wl_buffer is destroyed. Accessing this field
// should ensure wl_buffer exists by calling
// WaylandBufferManagerHost::EnsureBufferHandle(buffer_id).
raw_ptr<wl_buffer, AcrossTasksDanglingUntriaged> buffer = nullptr;
gfx::Size buffer_size_px;
// The buffer scale refers to the ratio between the buffer size and the
// window size. This allows support for high-DPI displays.
float buffer_scale_float = 1;
// Transformation for how the compositor interprets the contents of the
// buffer.
gfx::OverlayTransform buffer_transform = gfx::OVERLAY_TRANSFORM_NONE;
// Following fields are used to help determine the damage_region in
// surface-local coordinates if wl_surface_damage_buffer() is not available.
// Normalized bounds of the buffer to be displayed in |viewport_px|.
// If empty, no cropping is applied.
gfx::RectF crop = {0.f, 0.f};
// Current size of the destination of the viewport in physical pixels.
// Wayland compositor will scale the (cropped) buffer content to fit the
// |viewport_px|.
// If empty, no scaling is applied.
gfx::SizeF viewport_px = {0, 0};
// The opacity of the wl_surface used to call zcr_blending_v1_set_alpha.
float opacity = 1.f;
// The blending equation of the wl_surface used to call
// zcr_blending_v1_set_blending.
bool use_blending = true;
gfx::OverlayPriorityHint priority_hint = gfx::OverlayPriorityHint::kRegular;
// Whether or not this surface contains video, for wp_content_type_v1.
bool contains_video = false;
};
// The wayland scale refers to the scale factor between the buffer coordinates
// and Wayland surface coordinates. When SurfaceSubmissionInPixelCoordinates
// is true, this is always 1. Otherwise, this is buffer_scale_float unless the
// value is less than 1. In that case 1 is returned. Additionally, if
// viewporter surface scaling is disabled, the value will be rounded up to the
// next integer.
float GetWaylandScale(const State& state);
bool IsViewportScaled(const State& state);
bool SetExplicitSyncLegacy();
void EnsureSurfaceSync();
void EnsureAcquireTimeline();
// Returns whether explicit sync was set, or std::nullopt if there was some
// failure in setting explicit sync.
std::optional<bool> SetExplicitSync();
void OnFenceAvailable(uint32_t buffer_id,
ExplicitReleaseCallback callback,
base::ScopedFD fd);
// Tracks the last sent src and dst values across wayland protocol s.t. we
// skip resending them when possible.
wl_fixed_t src_set_[4] = {wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1)};
float dst_set_[2] = {-1.f, -1.f};
// Tracks the last sent surface_scale value s.t. we skip resending.
// This is used by wl_surface_set_buffer_scale which only supports integer
// scales.
int32_t surface_scale_set_ = 1;
wl::Object<wl_region> CreateAndAddRegion(
const std::vector<gfx::Rect>& region_px,
float buffer_scale);
// wl_surface states that are stored in Wayland client. It moves to |state_|
// on ApplyPendingState().
State pending_state_;
// wl_surface states that are either active or will be active once Commit() is
// called.
State state_;
const raw_ptr<WaylandConnection> connection_;
raw_ptr<WaylandWindow> root_window_ = nullptr;
bool apply_state_immediately_ = false;
wl::Object<wl_surface> surface_;
wl::Object<wp_viewport> viewport_;
wl::Object<zcr_blending_v1> blending_;
wl::Object<zwp_linux_surface_synchronization_v1> surface_sync_legacy_;
wl::Object<wp_linux_drm_syncobj_surface_v1> surface_sync_;
std::unique_ptr<WaylandSyncobjAcquireTimeline> acquire_timeline_;
wl::Object<overlay_prioritized_surface> overlay_priority_surface_;
wl::Object<wp_content_type_v1> content_type_;
wl::Object<wp_fractional_scale_v1> fractional_scale_;
std::unique_ptr<WaylandZcrColorManagementSurface>
zcr_color_management_surface_;
base::flat_map<zwp_linux_buffer_release_v1*, ExplicitReleaseInfoLegacy>
linux_buffer_releases_legacy_;
ExplicitReleaseCallback next_explicit_release_request_;
// A cached copy of connection->supports_viewporter_surface_scaling(). While
// it is technically possible to handle this value as mutable, in practice
// it's constant.
const bool use_viewporter_surface_scaling_;
// For top level window, stores outputs that the window is currently rendered
// at.
//
// Not used by popups. When sub-menus are hidden and shown again, Wayland
// 'repositions' them to wrong outputs by sending them leave and enter
// events so their list of entered outputs becomes meaningless after they have
// been hidden at least once. To determine which output the popup belongs to,
// we ask its parent.
std::vector<uint32_t> entered_outputs_;
// Holds the preferred buffer factor for this surface, if any was received
// through wp-fractional-scale-v1 protocol, when available.
std::optional<float> preferred_scale_factor_;
void ExplicitRelease(zwp_linux_buffer_release_v1* linux_buffer_release,
base::ScopedFD fence);
// wl_surface_listener callbacks:
static void OnEnter(void* data, wl_surface* surface, wl_output* output);
static void OnLeave(void* data, wl_surface* surface, wl_output* output);
// wp_fractional_scale_v1_listener callbacks:
static void OnPreferredScale(void* data,
wp_fractional_scale_v1* fractional_scale,
uint32_t scale);
// zwp_linux_buffer_release_v1_listener callbacks:
static void OnFencedRelease(void* data,
zwp_linux_buffer_release_v1* buffer_release,
int32_t fence);
static void OnImmediateRelease(void* data,
zwp_linux_buffer_release_v1* buffer_release);
base::WeakPtrFactory<WaylandSurface> weak_factory_{this};
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
|