From 1dac5454eacc4b0410e6a974cf8af437b95d3776 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Mon, 7 Feb 2022 17:54:57 +0800 Subject: [PATCH] glx: keep native window glx drawable by driconf option DRI3 window back buffer is a client resource, so it's destroyed when context switch drawable for native window. But some application like Abaqus may leave a dirty back buffer and reuse it when switch back. So add a driconf option for these kind of app to keep the entire GLX drawable for native window. Reviewed-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Qiang Yu Part-of: --- .../auxiliary/pipe-loader/driinfo_gallium.h | 1 + src/glx/dri3_glx.c | 7 +++ src/glx/dri_common.c | 52 ++++++++++++++++++- src/glx/glxclient.h | 7 +++ src/glx/glxext.c | 17 ++++++ src/util/driconf.h | 4 ++ 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/gallium/auxiliary/pipe-loader/driinfo_gallium.h b/src/gallium/auxiliary/pipe-loader/driinfo_gallium.h index e79da788178..067348a3733 100644 --- a/src/gallium/auxiliary/pipe-loader/driinfo_gallium.h +++ b/src/gallium/auxiliary/pipe-loader/driinfo_gallium.h @@ -49,6 +49,7 @@ DRI_CONF_SECTION_DEBUG DRI_CONF_IGNORE_MAP_UNSYNCHRONIZED(false) DRI_CONF_FORCE_DIRECT_GLX_CONTEXT(false) DRI_CONF_ALLOW_INVALID_GLX_DESTROY_WINDOW(false) + DRI_CONF_KEEP_NATIVE_WINDOW_GLX_DRAWABLE(false) DRI_CONF_SECTION_END DRI_CONF_SECTION_MISCELLANEOUS diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index dc7aba9c985..1623a10ce44 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -1055,6 +1055,13 @@ dri3_create_screen(int screen, struct glx_display * priv) &invalid_glx_destroy_window) == 0) { psc->base.allow_invalid_glx_destroy_window = invalid_glx_destroy_window; } + + uint8_t keep_native_window_glx_drawable = false; + if (psc->config->configQueryb(psc->driScreen, + "keep_native_window_glx_drawable", + &keep_native_window_glx_drawable) == 0) { + psc->base.keep_native_window_glx_drawable = keep_native_window_glx_drawable; + } } free(driverName); diff --git a/src/glx/dri_common.c b/src/glx/dri_common.c index fd52b0e347d..7e2809d0c79 100644 --- a/src/glx/dri_common.c +++ b/src/glx/dri_common.c @@ -357,6 +357,9 @@ driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) return NULL; if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { + /* Resurrected, so remove from the alive-query-set if exist. */ + _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw); + pdraw->refcount ++; return pdraw; } @@ -419,6 +422,46 @@ driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) return pdraw; } +static int +discardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes, + int *ret_code) +{ + int code = codes->first_error + GLXBadDrawable; + + /* Only discard error which is expected. */ + if (err->majorCode == codes->major_opcode && + err->minorCode == X_GLXGetDrawableAttributes && + /* newer xserver use GLXBadDrawable, old one use BadDrawable */ + (err->errorCode == code || err->errorCode == BadDrawable)) { + *ret_code = 1; + return 1; + } + + return 0; +} + +static void +checkServerGLXDrawableAlive(const struct glx_display *priv) +{ + ErrorType old = XESetError(priv->dpy, priv->codes.extension, + discardGLXBadDrawableHandler); + + set_foreach(priv->zombieGLXDrawable, entry) { + __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key; + GLXDrawable drawable = pdraw->drawable; + unsigned int dummy; + + /* Fail to query, so the window has been closed. Release the GLXDrawable. */ + if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) { + pdraw->destroyDrawable(pdraw); + __glxHashDelete(priv->drawHash, drawable); + _mesa_set_remove(priv->zombieGLXDrawable, entry); + } + } + + XESetError(priv->dpy, priv->codes.extension, old); +} + static void releaseDrawable(const struct glx_display *priv, GLXDrawable drawable) { @@ -433,8 +476,13 @@ releaseDrawable(const struct glx_display *priv, GLXDrawable drawable) * hold the last refcount until destroy the GLXPbuffer object. */ if (pdraw->refcount == 0) { - pdraw->destroyDrawable(pdraw); - __glxHashDelete(priv->drawHash, drawable); + if (pdraw->psc->keep_native_window_glx_drawable) { + checkServerGLXDrawableAlive(priv); + _mesa_set_add(priv->zombieGLXDrawable, pdraw); + } else { + pdraw->destroyDrawable(pdraw); + __glxHashDelete(priv->drawHash, drawable); + } } } } diff --git a/src/glx/glxclient.h b/src/glx/glxclient.h index 4ea091f986b..54c12a4227b 100644 --- a/src/glx/glxclient.h +++ b/src/glx/glxclient.h @@ -54,6 +54,7 @@ #include "glxhash.h" #include "util/macros.h" #include "util/u_thread.h" +#include "util/set.h" #include "loader.h" #include "glxextensions.h" @@ -524,6 +525,7 @@ struct glx_screen int scr; bool force_direct_context; bool allow_invalid_glx_destroy_window; + bool keep_native_window_glx_drawable; #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) /** @@ -595,6 +597,11 @@ struct glx_display #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) __glxHashTable *drawHash; + /** + * GLXDrawable created from native window and about to be released. + */ + struct set *zombieGLXDrawable; + /** * Per display direct rendering interface functions and data. */ diff --git a/src/glx/glxext.c b/src/glx/glxext.c index 48a60ad35cc..d828da227d4 100644 --- a/src/glx/glxext.c +++ b/src/glx/glxext.c @@ -268,6 +268,16 @@ FreeScreenConfigs(struct glx_display * priv) priv->screens = NULL; } +#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) +static void +free_zombie_glx_drawable(struct set_entry *entry) +{ + __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key; + + pdraw->destroyDrawable(pdraw); +} +#endif + static void glx_display_free(struct glx_display *priv) { @@ -279,6 +289,11 @@ glx_display_free(struct glx_display *priv) __glXSetCurrentContextNull(); } + /* Needs to be done before free screen. */ +#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) + _mesa_set_destroy(priv->zombieGLXDrawable, free_zombie_glx_drawable); +#endif + FreeScreenConfigs(priv); __glxHashDestroy(priv->glXDrawHash); @@ -914,6 +929,8 @@ __glXInitialize(Display * dpy) dpyPriv->drawHash = __glxHashCreate(); + dpyPriv->zombieGLXDrawable = _mesa_pointer_set_create(NULL); + #ifndef GLX_USE_APPLEGL /* Set the logger before the *CreateDisplay functions. */ loader_set_logger(glx_message); diff --git a/src/util/driconf.h b/src/util/driconf.h index 5e1c9591853..115430226e8 100644 --- a/src/util/driconf.h +++ b/src/util/driconf.h @@ -250,6 +250,10 @@ DRI_CONF_OPT_B(allow_invalid_glx_destroy_window, def, \ "Allow passing an invalid window into glXDestroyWindow") +#define DRI_CONF_KEEP_NATIVE_WINDOW_GLX_DRAWABLE(def) \ + DRI_CONF_OPT_B(keep_native_window_glx_drawable, def, \ + "Keep GLX drawable created from native window when switch context") + #define DRI_CONF_OVERRIDE_VRAM_SIZE() \ DRI_CONF_OPT_I(override_vram_size, -1, -1, 2147483647, \ "Override the VRAM size advertised to the application in MiB (-1 = default)")