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 <pierre-eric.pelloux-prayer@amd.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14926>
This commit is contained in:
Qiang Yu 2022-02-07 17:54:57 +08:00 committed by Marge Bot
parent 4a420c50f2
commit 1dac5454ea
6 changed files with 86 additions and 2 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}
}
}

View File

@ -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.
*/

View File

@ -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);

View File

@ -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)")