From ad90dbabe4ba2b42a86687b1c0ca5e8ffc6ece4c Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Tue, 11 Mar 2025 21:51:31 -0500 Subject: [PATCH] egl/kopper: Update the EGLSurface size after kopperSwapBuffers() Otherwise, the size of the EGLSurface and the drawable may get out of sync if kopper needs to re-create the swapchain at a different size. This can cause problems with things like eglSetDamageRegionKHR() where the core EGL code clamps them to the size in the EGLSurface. With Wayland, it's up to the client to choose a size and resize by creating a new EGLSurface with a different size. Only on X11 can we get a resize side-band like this. Normally, without kopper, this goes the other direction where the X11 EGL code will detect a surface size change in dri2_x11_query_surface() and it invalidates the drawable if they've changed, forcing re-allocation. Kopper, however, works more like the DRI2 path where we just get handed buffers at some size decided by X11 and have to deal with them. In the DRI2 path, the size is unconditionally updated by dri2_x11_get_buffers(). This is roughly equivalent, updating the size right after every call to kopperSwapBuffers(). Fixes: 8ade5588e39d ("zink: add kopper api") Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/12797 Reviewed-By: Mike Blumenkrantz Part-of: --- src/egl/drivers/dri2/platform_x11.c | 18 ++++++++++++++++++ src/gallium/frontends/dri/dri_util.h | 2 ++ src/gallium/frontends/dri/kopper.c | 7 +++++++ src/gallium/frontends/dri/kopper_stubs.c | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index b63e6d80412..d64fb04255b 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -1108,6 +1108,15 @@ dri2_x11_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) */ kopperSwapBuffers(dri2_surf->dri_drawable, __DRI2_FLUSH_INVALIDATE_ANCILLARY); + + /* If the X11 window has been resized, vkQueuePresentKHR() or + * vkAcquireNextImageKHR() may return VK_ERROR_SURFACE_LOST or + * VK_SUBOPTIMAL_KHR, causing kopper to re-create the swapchain with + * a different size. We need to resize the EGLSurface in that case. + */ + kopperQuerySurfaceSize(dri2_surf->dri_drawable, + &dri2_surf->base.Width, + &dri2_surf->base.Height); return EGL_TRUE; } else if (dri2_dpy->swrast) { /* aka the swrast path, which does the swap in the gallium driver. */ @@ -1137,6 +1146,15 @@ dri2_x11_kopper_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw, kopperSwapBuffersWithDamage(dri2_surf->dri_drawable, __DRI2_FLUSH_INVALIDATE_ANCILLARY, numRects, rects); else kopperSwapBuffers(dri2_surf->dri_drawable, __DRI2_FLUSH_INVALIDATE_ANCILLARY); + + /* If the X11 window has been resized, vkQueuePresentKHR() or + * vkAcquireNextImageKHR() may return VK_ERROR_SURFACE_LOST or + * VK_SUBOPTIMAL_KHR, causing kopper to re-create the swapchain with + * a different size. We need to resize the EGLSurface in that case. + */ + kopperQuerySurfaceSize(dri2_surf->dri_drawable, + &dri2_surf->base.Width, + &dri2_surf->base.Height); } else { if (numRects) driSwapBuffersWithDamage(dri2_surf->dri_drawable, numRects, rects); diff --git a/src/gallium/frontends/dri/dri_util.h b/src/gallium/frontends/dri/dri_util.h index 7458575bf25..f9220514dda 100644 --- a/src/gallium/frontends/dri/dri_util.h +++ b/src/gallium/frontends/dri/dri_util.h @@ -163,6 +163,8 @@ PUBLIC void kopperSetSwapInterval(struct dri_drawable *drawable, int interval); PUBLIC int kopperQueryBufferAge(struct dri_drawable *drawable); +PUBLIC void +kopperQuerySurfaceSize(struct dri_drawable *drawable, int *width, int *height); PUBLIC void driswCopySubBuffer(struct dri_drawable *drawable, int x, int y, int w, int h); diff --git a/src/gallium/frontends/dri/kopper.c b/src/gallium/frontends/dri/kopper.c index 39568b8a6dc..54a754c919d 100644 --- a/src/gallium/frontends/dri/kopper.c +++ b/src/gallium/frontends/dri/kopper.c @@ -663,6 +663,13 @@ kopperQueryBufferAge(struct dri_drawable *drawable) return zink_kopper_query_buffer_age(ctx->st->pipe, ptex); } +void +kopperQuerySurfaceSize(struct dri_drawable *drawable, int *width, int *height) +{ + *width = drawable->w; + *height = drawable->h; +} + int kopperGetSyncValues(struct dri_drawable *drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) diff --git a/src/gallium/frontends/dri/kopper_stubs.c b/src/gallium/frontends/dri/kopper_stubs.c index efa442ecc2e..0ebc17b02a0 100644 --- a/src/gallium/frontends/dri/kopper_stubs.c +++ b/src/gallium/frontends/dri/kopper_stubs.c @@ -26,6 +26,12 @@ kopperQueryBufferAge(struct dri_drawable *dPriv) return 0; } +void +kopperQuerySurfaceSize(struct dri_drawable *drawable, int *width, int *height) +{ + *width = *height = 1; +} + int kopperGetSyncValues(struct dri_drawable *drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)