xwayland: Replace window pixmap as needed for drawing operation
We must not modify the contents of a client pixmap.
If there's an available window buffer, we re-use that for the window
pixmap. Otherwise we just allocate a new one.
This also avoids Present client hangs due to xwl_present_buffer_release
not getting called for the buffer release event.
v2:
* Use xwl_pixmap_get_buffer_release_cb instead of keeping track of the
flip pixmap in xwl_window.
* Dispose of xwl_window_buffer in xwl_window_swap_pixmap called from
damage_report.
v3:
* Use xwl_window->surface_pixmap in damage_report.
v4:
* Don't re-use client pixmaps as window buffers.
* Clear xwl_window_buffer->pixmap before calling
xwl_window_buffer_maybe_dispose in xwl_window_swap_pixmap, to prevent
it from clearing the buffer release callback.
v5:
* Keep using xwl_window_buffers_get_pixmap in xwl_window_attach_buffer.
* Always keep a reference to the old window pixmap in _swap_pixmap,
drop it in damage_report.
Fixes: 6779ec5bf6
("xwayland: Use window pixmap as a window buffer")
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1633
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1644
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1314>
This commit is contained in:
parent
0e29cccf36
commit
6b290fa5d9
|
@ -45,4 +45,10 @@ void xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap);
|
|||
void xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer);
|
||||
Bool xwl_pixmap_init(void);
|
||||
|
||||
static inline Bool
|
||||
xwl_is_client_pixmap(PixmapPtr pixmap)
|
||||
{
|
||||
return clients[CLIENT_ID(pixmap->drawable.id)] != serverClient;
|
||||
}
|
||||
|
||||
#endif /* XWAYLAND_PIXMAP_H */
|
||||
|
|
|
@ -78,8 +78,7 @@ xwl_window_buffer_new(struct xwl_window *xwl_window)
|
|||
xwl_window_buffer->pixmap = NullPixmap;
|
||||
xwl_window_buffer->refcnt = 1;
|
||||
|
||||
xorg_list_append(&xwl_window_buffer->link_buffer,
|
||||
&xwl_window->window_buffers_available);
|
||||
xorg_list_init(&xwl_window_buffer->link_buffer);
|
||||
|
||||
return xwl_window_buffer;
|
||||
}
|
||||
|
@ -331,7 +330,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window)
|
|||
screen->DestroyPixmap(window_pixmap);
|
||||
}
|
||||
|
||||
static PixmapPtr
|
||||
PixmapPtr
|
||||
xwl_window_swap_pixmap(struct xwl_window *xwl_window)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
||||
|
@ -360,17 +359,27 @@ 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->window, xwl_window_buffer->pixmap);
|
||||
|
||||
/* Can't re-use client pixmap as a window buffer */
|
||||
if (xwl_is_client_pixmap(window_pixmap)) {
|
||||
xwl_window_buffer->pixmap = NULL;
|
||||
xwl_window_buffer_maybe_dispose(xwl_window_buffer);
|
||||
return window_pixmap;
|
||||
}
|
||||
} else {
|
||||
/* Can't re-use client pixmap as a window buffer */
|
||||
if (!xwl_is_client_pixmap(window_pixmap))
|
||||
xwl_window_buffer = xwl_window_buffer_new(xwl_window);
|
||||
|
||||
window_pixmap->refcnt++;
|
||||
xwl_window_realloc_pixmap(xwl_window);
|
||||
|
||||
xwl_window_buffer = xwl_window_buffer_new(xwl_window);
|
||||
if (!xwl_window_buffer)
|
||||
return window_pixmap;
|
||||
}
|
||||
|
||||
xorg_list_del(&xwl_window_buffer->link_buffer);
|
||||
xwl_window_set_pixmap(xwl_window->window, xwl_window_buffer->pixmap);
|
||||
xwl_window_buffer->pixmap = window_pixmap;
|
||||
|
||||
/* Hold a reference on the buffer until it's released by the compositor */
|
||||
|
|
|
@ -31,10 +31,13 @@
|
|||
|
||||
#include "xwayland-types.h"
|
||||
|
||||
struct xwl_window_buffer;
|
||||
|
||||
void xwl_window_buffer_add_damage_region(struct xwl_window *xwl_window);
|
||||
void xwl_window_buffers_init(struct xwl_window *xwl_window);
|
||||
void xwl_window_buffers_dispose(struct xwl_window *xwl_window);
|
||||
void xwl_window_realloc_pixmap(struct xwl_window *xwl_window);
|
||||
PixmapPtr xwl_window_swap_pixmap(struct xwl_window *xwl_window);
|
||||
PixmapPtr xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window);
|
||||
|
||||
#endif /* XWAYLAND_WINDOW_BUFFERS_H */
|
||||
|
|
|
@ -188,6 +188,7 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
|
|||
WindowPtr window = data;
|
||||
struct xwl_window *xwl_window = xwl_window_get(window);
|
||||
struct xwl_screen *xwl_screen;
|
||||
PixmapPtr window_pixmap;
|
||||
|
||||
if (!xwl_window)
|
||||
return;
|
||||
|
@ -207,6 +208,10 @@ 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->window);
|
||||
if (xwl_is_client_pixmap(window_pixmap))
|
||||
xwl_screen->screen->DestroyPixmap(xwl_window_swap_pixmap(xwl_window));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -227,7 +232,6 @@ register_damage(WindowPtr window)
|
|||
}
|
||||
|
||||
DamageRegister(&window->drawable, damage);
|
||||
DamageSetReportAfterOp(damage, TRUE);
|
||||
|
||||
dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, damage);
|
||||
|
||||
|
|
Loading…
Reference in New Issue