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:
parent
db248682b3
commit
3a0fc2684a
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ struct xwl_screen {
|
|||
int nokeymap;
|
||||
int hidpi;
|
||||
|
||||
ClipNotifyProcPtr ClipNotify;
|
||||
CreateScreenResourcesProcPtr CreateScreenResources;
|
||||
CloseScreenProcPtr CloseScreen;
|
||||
CreateWindowProcPtr CreateWindow;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue