xwayland: Add xwl_window::surface_window

It may track a non-toplevel window which fully covers the area of the
window pixmap / Wayland surface. It is now used instead of
xwl_window::toplevel for updating the Wayland surface contents.

The surface_window can now hit the Present page flip path while it's
automatically redirected.

v2:
* Use "surface_window" instead of "surf_win". (Olivier Fourdan)
* Add comment describing surface_window, and describe what
  surface_window/toplevel are useful for respectively. (Olivier Fourdan)
* Use surface_window in xwl_realize_window.
v3:
* Backtrack up to the closest opaque ancestor in
  xwl_window_update_surface_window. (Olivier Fourdan)
v4:
* Clean up logic for determining the surface window in
  xwl_window_update_surface_window, and document it better.
* Handle window_get_damage(xwl_window->surface_window) returning NULL
  in xwl_window_update_surface_window.
* Call xwl_window_update_surface_window after xwl_window_buffers_init
  in ensure_surface_for_window, since the former may call
  xwl_window_buffers_dispose.
* Rename surf/win_pix to surface/window_pixmap in
  xwl_window_update_surface_window.

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>
This commit is contained in:
Michel Dänzer 2023-12-22 19:00:42 +01:00 committed by Marge Bot
parent db248682b3
commit 3a0fc2684a
8 changed files with 129 additions and 30 deletions

View File

@ -735,7 +735,7 @@ xwl_window_dmabuf_feedback_done(void *data,
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
{
struct xwl_window *xwl_window = data;
uint32_t format = wl_drm_format_for_depth(xwl_window->toplevel->drawable.depth);
uint32_t format = wl_drm_format_for_depth(xwl_window->surface_window->drawable.depth);
xwl_dmabuf_feedback_done(&xwl_window->feedback, dmabuf_feedback);
@ -743,7 +743,7 @@ xwl_window_dmabuf_feedback_done(void *data,
xwl_feedback_is_modifier_supported(&xwl_window->feedback, format,
DRM_FORMAT_MOD_INVALID, TRUE);
DebugF("XWAYLAND: Window 0x%x can%s get implicit scanout support\n",
xwl_window->toplevel->drawable.id,
xwl_window->surface_window->drawable.id,
xwl_window->has_implicit_scanout_support ? "" : "not");
/* If the linux-dmabuf v4 per-surface feedback changed, make sure the

View File

@ -412,7 +412,7 @@ PixmapPtr
xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
WindowPtr window = xwl_window->toplevel;
WindowPtr window = xwl_window->surface_window;
unsigned border_width = 2 * window->borderWidth;
if (!xwl_screen->glamor)

View File

@ -785,7 +785,7 @@ xwl_present_check_flip(RRCrtcPtr crtc,
* window's, e.g. because a client redirected this window or one of its
* parents.
*/
if (screen->GetWindowPixmap(xwl_window->toplevel) != screen->GetWindowPixmap(present_window))
if (screen->GetWindowPixmap(xwl_window->surface_window) != screen->GetWindowPixmap(present_window))
return FALSE;
/*

View File

@ -1110,6 +1110,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
xwl_screen->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
pScreen->ChangeWindowAttributes = xwl_change_window_attributes;
xwl_screen->ClipNotify = pScreen->ClipNotify;
pScreen->ClipNotify = xwl_clip_notify;
xwl_screen->ResizeWindow = pScreen->ResizeWindow;
pScreen->ResizeWindow = xwl_resize_window;

View File

@ -68,6 +68,7 @@ struct xwl_screen {
int nokeymap;
int hidpi;
ClipNotifyProcPtr ClipNotify;
CreateScreenResourcesProcPtr CreateScreenResources;
CloseScreenProcPtr CloseScreen;
CreateWindowProcPtr CreateWindow;

View File

@ -339,7 +339,7 @@ xwl_window_allocate_pixmap(struct xwl_window *xwl_window)
return window_pixmap;
#endif /* XWL_HAS_GLAMOR */
window_pixmap = screen->GetWindowPixmap(xwl_window->toplevel);
window_pixmap = screen->GetWindowPixmap(xwl_window->surface_window);
return screen->CreatePixmap(screen,
window_pixmap->drawable.width,
window_pixmap->drawable.height,
@ -358,7 +358,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
if (!new_window_pixmap)
return;
window = xwl_window->toplevel;
window = xwl_window->surface_window;
screen = window->drawable.pScreen;
window_pixmap = screen->GetWindowPixmap(window);
copy_pixmap_area(window_pixmap,
@ -366,7 +366,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
0, 0,
window_pixmap->drawable.width,
window_pixmap->drawable.height);
xwl_window_set_pixmap(xwl_window->toplevel, new_window_pixmap);
xwl_window_set_pixmap(xwl_window->surface_window, new_window_pixmap);
screen->DestroyPixmap(window_pixmap);
}
@ -414,11 +414,12 @@ PixmapPtr
xwl_window_swap_pixmap(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
WindowPtr surface_window = xwl_window->surface_window;
struct xwl_window_buffer *xwl_window_buffer;
PixmapPtr window_pixmap;
Bool implicit_sync = TRUE;
window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->toplevel);
window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (surface_window);
xwl_window_buffer_add_damage_region(xwl_window);
@ -441,8 +442,8 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
while (nBox--) {
copy_pixmap_area(window_pixmap,
xwl_window_buffer->pixmap,
pBox->x1 + xwl_window->toplevel->borderWidth,
pBox->y1 + xwl_window->toplevel->borderWidth,
pBox->x1 + surface_window->borderWidth,
pBox->y1 + surface_window->borderWidth,
pBox->x2 - pBox->x1,
pBox->y2 - pBox->y1);
@ -451,7 +452,7 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
RegionEmpty(xwl_window_buffer->damage_region);
xorg_list_del(&xwl_window_buffer->link_buffer);
xwl_window_set_pixmap(xwl_window->toplevel, xwl_window_buffer->pixmap);
xwl_window_set_pixmap(surface_window, xwl_window_buffer->pixmap);
/* Can't re-use client pixmap as a window buffer */
if (xwl_is_client_pixmap(window_pixmap)) {

View File

@ -87,7 +87,7 @@ window_get_damage(WindowPtr window)
RegionPtr
xwl_window_get_damage_region(struct xwl_window *xwl_window)
{
return DamageRegion(window_get_damage(xwl_window->toplevel));
return DamageRegion(window_get_damage(xwl_window->surface_window));
}
struct xwl_window *
@ -135,7 +135,7 @@ xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
DebugF("XWAYLAND: win %d allow_commits = %d (%s)\n",
xwl_window->toplevel->drawable.id, allow, debug_msg);
damage = window_get_damage(xwl_window->toplevel);
damage = window_get_damage(xwl_window->surface_window);
if (allow &&
xorg_list_is_empty(&xwl_window->link_damage) &&
damage &&
@ -202,7 +202,7 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
if (xorg_list_is_empty(&xwl_window->link_damage))
xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list);
window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->toplevel);
window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->surface_window);
if (xwl_is_client_pixmap(window_pixmap))
xwl_screen->screen->DestroyPixmap(xwl_window_swap_pixmap(xwl_window));
}
@ -215,18 +215,18 @@ damage_destroy(DamagePtr pDamage, void *data)
static Bool
register_damage(struct xwl_window *xwl_window)
{
WindowPtr toplevel = xwl_window->toplevel;
WindowPtr surface_window = xwl_window->surface_window;
DamagePtr damage;
damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty,
FALSE, toplevel->drawable.pScreen, xwl_window);
FALSE, surface_window->drawable.pScreen, xwl_window);
if (damage == NULL) {
ErrorF("Failed creating damage\n");
return FALSE;
}
DamageRegister(&toplevel->drawable, damage);
dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, damage);
DamageRegister(&surface_window->drawable, damage);
dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, damage);
return TRUE;
}
@ -234,17 +234,17 @@ register_damage(struct xwl_window *xwl_window)
static void
unregister_damage(struct xwl_window *xwl_window)
{
WindowPtr toplevel = xwl_window->toplevel;
WindowPtr surface_window = xwl_window->surface_window;
DamagePtr damage;
damage = dixLookupPrivate(&toplevel->devPrivates, &xwl_damage_private_key);
damage = dixLookupPrivate(&surface_window->devPrivates, &xwl_damage_private_key);
if (!damage)
return;
DamageUnregister(damage);
DamageDestroy(damage);
dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, NULL);
dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL);
}
static Bool
@ -540,15 +540,15 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
Bool
xwl_window_is_toplevel(WindowPtr window)
{
if (window_is_wm_window(window))
if (!window->parent || window_is_wm_window(window))
return FALSE;
/* CSD and override-redirect toplevel windows */
if (window_get_damage(window))
if (!window->parent->parent)
return TRUE;
/* Normal toplevel client windows, reparented to a window-manager window */
return window->parent && window_is_wm_window(window->parent);
return window_is_wm_window(window->parent);
}
static void
@ -1221,6 +1221,65 @@ err_surf:
return FALSE;
}
static void
xwl_window_update_surface_window(struct xwl_window *xwl_window)
{
WindowPtr surface_window = xwl_window->toplevel;
ScreenPtr screen = surface_window->drawable.pScreen;
PixmapPtr surface_pixmap;
DamagePtr window_damage;
RegionRec damage_region;
WindowPtr window;
surface_pixmap = screen->GetWindowPixmap(surface_window);
for (window = surface_window->firstChild; window; window = window->firstChild) {
PixmapPtr window_pixmap;
if (!RegionEqual(&window->winSize, &surface_window->winSize))
break;
/* The surface window must be top-level for its window pixmap */
window_pixmap = screen->GetWindowPixmap(window);
if (window_pixmap == surface_pixmap)
continue;
surface_pixmap = window_pixmap;
/* A descendant with alpha channel cannot be the surface window, since
* any non-opaque areas need to take the contents of ancestors into
* account.
*/
if (window->drawable.depth == 32)
continue;
surface_window = window;
}
if (xwl_window->surface_window == surface_window)
return;
window_damage = window_get_damage(xwl_window->surface_window);
if (window_damage) {
RegionInit(&damage_region, NullBox, 1);
RegionCopy(&damage_region, DamageRegion(window_damage));
unregister_damage(xwl_window);
}
if (surface_window->drawable.depth != xwl_window->surface_window->drawable.depth)
xwl_window_buffers_dispose(xwl_window);
xwl_window->surface_window = surface_window;
register_damage(xwl_window);
if (window_damage) {
RegionPtr new_region = DamageRegion(window_get_damage(surface_window));
RegionUnion(new_region, new_region, &damage_region);
RegionUninit(&damage_region);
}
}
static struct xwl_window *
ensure_surface_for_window(WindowPtr window)
{
@ -1250,6 +1309,7 @@ ensure_surface_for_window(WindowPtr window)
xwl_window->xwl_screen = xwl_screen;
xwl_window->toplevel = window;
xwl_window->surface_window = window;
xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR;
xwl_window->viewport_scale_x = 1.0;
xwl_window->viewport_scale_y = 1.0;
@ -1290,6 +1350,8 @@ ensure_surface_for_window(WindowPtr window)
xwl_window_buffers_init(xwl_window);
xwl_window_update_surface_window(xwl_window);
xwl_window_init_allow_commits(xwl_window);
/* When a new window-manager window is realized, then the randr emulation
@ -1360,7 +1422,7 @@ xwl_realize_window(WindowPtr window)
if (!xwl_window)
return FALSE;
if (window == xwl_window->toplevel &&
if (window == xwl_window->surface_window &&
!window_get_damage(window))
return register_damage(xwl_window);
@ -1571,6 +1633,22 @@ xwl_change_window_attributes(WindowPtr window, unsigned long mask)
return ret;
}
void
xwl_clip_notify(WindowPtr window, int dx, int dy)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_window *xwl_window = xwl_window_from_window(window);
screen->ClipNotify = xwl_screen->ClipNotify;
(*screen->ClipNotify) (window, dx, dy);
xwl_screen->ClipNotify = screen->ClipNotify;
screen->ClipNotify = xwl_clip_notify;
if (xwl_window)
xwl_window_update_surface_window(xwl_window);
}
void
xwl_resize_window(WindowPtr window,
int x, int y,
@ -1696,6 +1774,7 @@ static Bool
xwl_window_attach_buffer(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
WindowPtr surface_window = xwl_window->surface_window;
RegionPtr region;
BoxPtr box;
struct wl_buffer *buffer;
@ -1720,15 +1799,15 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window)
if (RegionNumRects(region) > 256) {
box = RegionExtents(region);
xwl_surface_damage(xwl_screen, xwl_window->surface,
box->x1 + xwl_window->toplevel->borderWidth,
box->y1 + xwl_window->toplevel->borderWidth,
box->x1 + surface_window->borderWidth,
box->y1 + surface_window->borderWidth,
box->x2 - box->x1, box->y2 - box->y1);
} else {
box = RegionRects(region);
for (i = 0; i < RegionNumRects(region); i++, box++) {
xwl_surface_damage(xwl_screen, xwl_window->surface,
box->x1 + xwl_window->toplevel->borderWidth,
box->y1 + xwl_window->toplevel->borderWidth,
box->x1 + surface_window->borderWidth,
box->y1 + surface_window->borderWidth,
box->x2 - box->x1, box->y2 - box->y1);
}
}
@ -1745,7 +1824,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
return;
xwl_window_create_frame_callback(xwl_window);
DamageEmpty(window_get_damage(xwl_window->toplevel));
DamageEmpty(window_get_damage(xwl_window->surface_window));
}
Bool

View File

@ -66,9 +66,23 @@ struct xwl_window {
/* Top-level window for the Wayland surface:
* - With rootful, the root window itself
* - With rootless, a direct child of the root window
* Mainly useful when the top-level window is needed, can also be used for
* the X dimensions of the Wayland surface though.
*/
WindowPtr toplevel;
/* The window associated with the Wayland surface:
* - If the top-level window has descendants which:
* - Cover it completely
* - Have no alpha channel
* - Use a different window pixmap than their parent for storage
* then the surface window is the lowest-level such descendant.
* - Otherwise it's the top-level window itself.
* Mainly useful for code dealing with (buffers for) the Wayland surface,
* can also be used for the X dimensions of the Wayland surface though.
*/
WindowPtr surface_window;
struct xorg_list link_damage;
struct xorg_list link_window;
struct wl_callback *frame_callback;
@ -114,6 +128,7 @@ int xwl_window_get_max_output_scale(struct xwl_window *xwl_window);
Bool xwl_realize_window(WindowPtr window);
Bool xwl_unrealize_window(WindowPtr window);
Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask);
void xwl_clip_notify(WindowPtr window, int dx, int dy);
void xwl_resize_window(WindowPtr window,
int x, int y,
unsigned int width, unsigned int height,