Skip to content
Snippets Groups Projects

Add multiple buffering to xwl_window

Merged Olivier Fourdan requested to merge ofourdan/xserver:issue835 into master
2 files
+ 109
1
Compare changes
  • Side-by-side
  • Inline
Files
2
  • a1e5c3fd
    Xwayland takes care of not attaching a new buffer if a frame callback is
    pending.
    
    Yet, the existing buffer (which was previously attached) may still be
    updated from the X11 side, causing unexpected visual glitches to the
    buffer.
    
    Add double buffering to the xwl_window and alternate between buffers,
    to leave the Wayland buffer untouched between frame callbacks and avoid
    stuttering or tearing issues.
    
    !316
    Closes: #835
    
    
    Signed-off-by: default avatarOlivier Fourdan <ofourdan@redhat.com>
+ 106
1
@@ -547,6 +547,107 @@ static const struct wl_shell_surface_listener shell_surface_listener = {
shell_surface_popup_done
};
static Bool
copy_pixmap_area(PixmapPtr src_pixmap, PixmapPtr dst_pixmap,
int x, int y, int width, int height)
{
GCPtr pGC;
pGC = GetScratchGC(dst_pixmap->drawable.depth,
dst_pixmap->drawable.pScreen);
if (pGC) {
ValidateGC(&dst_pixmap->drawable, pGC);
(void) (*pGC->ops->CopyArea) (&src_pixmap->drawable,
&dst_pixmap->drawable,
pGC,
x, y,
width, height,
x, y);
FreeScratchGC(pGC);
return TRUE;
}
return FALSE;
}
static PixmapPtr
xwl_window_get_pixmap_buffer(struct xwl_window *xwl_window,
RegionPtr damage_region)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
PixmapPtr window_pixmap;
PixmapPtr ret_pixmap;
window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
/* In case something goes bad, fallback to the window pixmap */
ret_pixmap = window_pixmap;
/* 1. Alternate buffers */
xwl_window->current_buffer = (xwl_window->current_buffer + 1) % 2;
/* 2. Add the new damage region to the previous one to get full updates */
RegionUnion(xwl_window->prev_damage_region,
xwl_window->prev_damage_region,
damage_region);
/* 3. Copy areas based on the previous and new damage regions */
if (xwl_window->pixmap[xwl_window->current_buffer]) {
BoxPtr pBox = RegionRects(xwl_window->prev_damage_region);
int nBox = RegionNumRects(xwl_window->prev_damage_region);
while (nBox--) {
if (!copy_pixmap_area(window_pixmap,
xwl_window->pixmap[xwl_window->current_buffer],
pBox->x1, pBox->y1,
pBox->x2 - pBox->x1, pBox->y2 - pBox->y1))
goto failsafe;
pBox++;
}
} else {
xwl_window->pixmap[xwl_window->current_buffer] =
(*xwl_screen->screen->CreatePixmap) (window_pixmap->drawable.pScreen,
window_pixmap->drawable.width,
window_pixmap->drawable.height,
window_pixmap->drawable.depth,
CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
if (!xwl_window->pixmap[xwl_window->current_buffer])
goto failsafe;
/* Copy everything */
if (!copy_pixmap_area(window_pixmap,
xwl_window->pixmap[xwl_window->current_buffer],
0, 0,
window_pixmap->drawable.width,
window_pixmap->drawable.height))
goto failsafe;
}
ret_pixmap = xwl_window->pixmap[xwl_window->current_buffer];
failsafe:
/* 4. Save the new damage region for the other buffer */
RegionCopy(xwl_window->prev_damage_region, damage_region);
return ret_pixmap;
}
static void
xwl_window_free_pixmap_buffers(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
ScreenPtr pScreen = xwl_screen->screen;
unsigned short i;
for (i = 0; i < 2; i++) {
if (xwl_window->pixmap[i]) {
(*pScreen->DestroyPixmap) (xwl_window->pixmap[i]);
xwl_window->pixmap[i] = NULL;
}
}
}
void
xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap)
{
@@ -855,6 +956,7 @@ ensure_surface_for_window(WindowPtr window)
dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window);
xorg_list_init(&xwl_window->link_damage);
xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list);
xwl_window->prev_damage_region = RegionCreate(NullBox, 1);
xwl_window_init_allow_commits(xwl_window);
@@ -954,10 +1056,12 @@ xwl_unrealize_window(WindowPtr window)
if (xwl_window_has_viewport_enabled(xwl_window))
xwl_window_disable_viewport(xwl_window);
xwl_window_free_pixmap_buffers(xwl_window);
wl_surface_destroy(xwl_window->surface);
xorg_list_del(&xwl_window->link_damage);
xorg_list_del(&xwl_window->link_window);
unregister_damage(window);
RegionDestroy(xwl_window->prev_damage_region);
if (xwl_window->frame_callback)
wl_callback_destroy(xwl_window->frame_callback);
@@ -1007,6 +1111,7 @@ xwl_resize_window(WindowPtr window,
screen->ResizeWindow = xwl_resize_window;
if (xwl_window) {
xwl_window_free_pixmap_buffers(xwl_window);
xwl_window->x = x;
xwl_window->y = y;
xwl_window->width = width;
@@ -1078,7 +1183,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
assert(!xwl_window->frame_callback);
region = DamageRegion(window_get_damage(xwl_window->window));
pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
pixmap = xwl_window_get_pixmap_buffer(xwl_window, region);
#ifdef XWL_HAS_GLAMOR
if (xwl_screen->glamor)
Loading