-
Notifications
You must be signed in to change notification settings - Fork 6.6k
/
wayland_surface.h
400 lines (330 loc) · 15.9 KB
/
wayland_surface.h
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
// 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 <vector>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/files/scoped_file.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkColor.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 zwp_keyboard_shortcuts_inhibitor_v1;
struct zwp_linux_buffer_release_v1;
struct zcr_blending_v1;
namespace ui {
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();
// 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 nullptr or empty, the opaque region is
// reset to empty.
void set_opaque_region(const 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(const 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 the rounded clip bounds for this surface.
void set_rounded_clip_bounds(const gfx::RRectF& rounded_clip_bounds) {
if (get_augmented_surface())
pending_state_.rounded_clip_bounds = rounded_clip_bounds;
}
// Sets the background color for this surface, which will be blended with the
// wl_buffer contents during the compositing step on the Wayland compositor
// side.
void set_background_color(absl::optional<SkColor4f> background_color) {
if (get_augmented_surface())
pending_state_.background_color = background_color;
}
// 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_|.
void 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);
private:
FRIEND_TEST_ALL_PREFIXES(WaylandWindowTest,
DoesNotCreateSurfaceSyncOnCommitWithoutBuffers);
// Holds information about each explicit synchronization buffer release.
struct ExplicitReleaseInfo {
ExplicitReleaseInfo(
wl::Object<zwp_linux_buffer_release_v1>&& linux_buffer_release,
wl_buffer* buffer,
ExplicitReleaseCallback explicit_release_callback);
~ExplicitReleaseInfo();
ExplicitReleaseInfo(const ExplicitReleaseInfo&) = delete;
ExplicitReleaseInfo& operator=(const ExplicitReleaseInfo&) = delete;
ExplicitReleaseInfo(ExplicitReleaseInfo&&);
ExplicitReleaseInfo& operator=(ExplicitReleaseInfo&&);
wl::Object<zwp_linux_buffer_release_v1> linux_buffer_release;
// The buffer associated with this explicit release.
raw_ptr<wl_buffer, DanglingUntriaged> 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;
absl::optional<gfx::Rect> input_region_px = absl::nullopt;
// 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, DanglingUntriaged> 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::RRectF rounded_clip_bounds;
gfx::OverlayPriorityHint priority_hint = gfx::OverlayPriorityHint::kRegular;
// Optional background color for this surface. This information
// can be used by Wayland compositor to correctly display delegated textures
// which require background color applied.
absl::optional<SkColor4f> background_color;
// Whether or not this surface contains video, for wp_content_type_v1.
bool contains_video = false;
};
// The wayland scale refers to the scale factor used for calls to wayland
// apis such as wl_region_add. When SurfaceSubmissionInPixelCoordinates is
// true, this is always 1. Otherwise this is buffer_scale_float casted to an
// integer.
int GetWaylandScale(const State& state);
// 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,
int32_t 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_;
// Creates (if not created) the synchronization surface and returns a pointer
// to it.
zwp_linux_surface_synchronization_v1* GetOrCreateSurfaceSync();
augmented_surface* get_augmented_surface() {
return augmented_surface_.get();
}
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_keyboard_shortcuts_inhibitor_v1> keyboard_shortcuts_inhibitor_;
wl::Object<zwp_linux_surface_synchronization_v1> surface_sync_;
wl::Object<overlay_prioritized_surface> overlay_priority_surface_;
wl::Object<augmented_surface> augmented_surface_;
wl::Object<wp_content_type_v1> content_type_;
std::unique_ptr<WaylandZcrColorManagementSurface>
zcr_color_management_surface_;
base::flat_map<zwp_linux_buffer_release_v1*, ExplicitReleaseInfo>
linux_buffer_releases_;
ExplicitReleaseCallback next_explicit_release_request_;
// A cached copy of connection->SurfaceSubmissionInPixelCoordinates(). While
// it is technically possible to handle this value as mutable, in practice
// it's constant.
const bool surface_submission_in_pixel_coordinates_;
// 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_;
void ExplicitRelease(struct zwp_linux_buffer_release_v1* linux_buffer_release,
base::ScopedFD fence);
// wl_surface_listener
static void Enter(void* data,
struct wl_surface* wl_surface,
struct wl_output* output);
static void Leave(void* data,
struct wl_surface* wl_surface,
struct wl_output* output);
// zwp_linux_buffer_release_v1_listener
static void FencedRelease(
void* data,
struct zwp_linux_buffer_release_v1* linux_buffer_release,
int32_t fence);
static void ImmediateRelease(
void* data,
struct zwp_linux_buffer_release_v1* linux_buffer_release);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_