mirror of
https://github.com/X11Libre/xserver.git
synced 2026-04-14 17:18:09 +00:00
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>
(cherry picked from commit 3a0fc2684a)
This commit is contained in:
committed by
Alan Coopersmith
parent
1762048b4b
commit
f86a1e565f
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user