From 5b953c0c3178f229c6acfd353169ecb0e2d4d987 Mon Sep 17 00:00:00 2001
From: Olivier Blin <oblin@mandriva.com>
Date: Mon, 28 Aug 2006 19:11:23 -0300
Subject: [PATCH] happy vt switch

fix freeze on VT switch when using AIGLX (#24559) using temporary patch from
https://bugs.freedesktop.org/show_bug.cgi?id=7916
---
 GL/glx/glxdri.c    |   54 ++++++++++++++++++++++++++------
 GL/glx/glxext.c    |   87 +++++++++++++++++++++++++++++++++++++++-------------
 GL/glx/glxserver.h |    3 ++
 3 files changed, 112 insertions(+), 32 deletions(-)

diff --git a/GL/glx/glxdri.c b/GL/glx/glxdri.c
index dc6cc70..99e1e92 100644
--- a/GL/glx/glxdri.c
+++ b/GL/glx/glxdri.c
@@ -63,27 +63,30 @@ #include "dispatch.h"
 #define STRINGIFY(macro_or_string)	STRINGIFY_ARG (macro_or_string)
 #define	STRINGIFY_ARG(contents)	#contents
 
-typedef struct __GLXDRIscreen      __GLXDRIscreen;
-typedef struct __GLXDRIcontext         __GLXDRIcontext;
+typedef struct __GLXDRIscreen   __GLXDRIscreen;
+typedef struct __GLXDRIcontext  __GLXDRIcontext;
 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
 
 struct __GLXDRIscreen {
-    __GLXscreen		 base;
+    __GLXscreen	     base;
 
-    __DRIscreen			 driScreen;
-    void			*driver;
+    xf86EnterVTProc *enterVT;
+    xf86LeaveVTProc *leaveVT;
+
+    __DRIscreen	     driScreen;
+    void	    *driver;
 };
 
 struct __GLXDRIcontext {
-    __GLXcontext		 base;
+    __GLXcontext base;
 
-    __DRIcontext		 driContext;
+    __DRIcontext driContext;
 };
 
 struct __GLXDRIdrawable {
-    __GLXdrawable	 base;
+    __GLXdrawable  base;
 
-    __DRIdrawable		*driDrawable;
+    __DRIdrawable *driDrawable;
 };
 
 /* History:
@@ -599,8 +602,7 @@ static __DRIfuncPtr getProcAddress(const
 
 static __DRIscreen *findScreen(__DRInativeDisplay *dpy, int scrn)
 {
-    __GLXDRIscreen *screen =
-	(__GLXDRIscreen *) __glXgetActiveScreen(scrn);
+    __GLXDRIscreen *screen = (__GLXDRIscreen *) __glXgetActiveScreen(scrn);
 
     return &screen->driScreen;
 }
@@ -794,6 +796,30 @@ static const __DRIinterfaceMethods inter
 
 static const char dri_driver_path[] = DRI_DRIVER_PATH;
 
+static Bool
+glxDRIEnterVT (int index, int flags)
+{
+    __GLXDRIscreen *screen = (__GLXDRIscreen *) __glXgetActiveScreen(index);
+
+    LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
+
+    glxResumeClients();
+
+    return (*screen->enterVT) (index, flags);
+}
+
+static void
+glxDRILeaveVT (int index, int flags)
+{
+    __GLXDRIscreen *screen = (__GLXDRIscreen *) __glXgetActiveScreen(index);
+
+    LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
+
+    glxSuspendClients();
+
+    return (*screen->leaveVT) (index, flags);
+}
+
 static __GLXscreen *
 __glXDRIscreenProbe(ScreenPtr pScreen)
 {
@@ -818,6 +844,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen)
     void *dev_priv = NULL;
     char filename[128];
     Bool isCapable;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 
     if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable")) {
 	LogMessage(X_ERROR, "AIGLX: DRI module not loaded\n");
@@ -987,6 +1014,11 @@ __glXDRIscreenProbe(ScreenPtr pScreen)
 
     __glXsetEnterLeaveServerFuncs(__glXDRIenterServer, __glXDRIleaveServer);
 
+    screen->enterVT = pScrn->EnterVT;
+    pScrn->EnterVT = glxDRIEnterVT; 
+    screen->leaveVT = pScrn->LeaveVT;
+    pScrn->LeaveVT = glxDRILeaveVT;
+
     LogMessage(X_INFO,
 	       "AIGLX: Loaded and initialized %s\n", filename);
 
diff --git a/GL/glx/glxext.c b/GL/glx/glxext.c
index cc5dd96..cda2727 100644
--- a/GL/glx/glxext.c
+++ b/GL/glx/glxext.c
@@ -33,8 +33,6 @@ #include "unpack.h"
 #include "glxutil.h"
 #include "glxext.h"
 
-static Bool inDispatch;
-
 /*
 ** Forward declarations.
 */
@@ -190,6 +188,10 @@ static Bool DrawableGone(__GLXdrawable *
     return True;
 }
 
+static __GLXcontext *glxPendingDestroyContexts;
+static int glxServerLeaveCount;
+static int glxBlockClients;
+
 /*
 ** Free a context.
 */
@@ -207,13 +209,14 @@ GLboolean __glXFreeContext(__GLXcontext 
      * __glXDispatch() or as a callback from the resource manager.  In
      * the latter case we need to lift the DRI lock manually. */
 
-    if (!inDispatch)
-      __glXleaveServer();
-
-    cx->destroy(cx);
-
-    if (!inDispatch)
-      __glXenterServer();
+    if (glxBlockClients) {
+	__glXleaveServer();
+	cx->destroy(cx);
+	__glXenterServer();
+    } else {
+	cx->next = glxPendingDestroyContexts;
+	glxPendingDestroyContexts = cx;
+    }
 
     return GL_TRUE;
 }
@@ -312,7 +315,7 @@ void GlxExtensionInit(void)
     /*
     ** Initialize table of client state.  There is never a client 0.
     */
-    for (i=1; i <= MAXCLIENTS; i++) {
+    for (i = 1; i <= MAXCLIENTS; i++) {
 	__glXClients[i] = 0;
     }
 
@@ -383,11 +386,43 @@ __GLXcontext *__glXForceCurrent(__GLXcli
 
 /************************************************************************/
 
-/*
-** Top level dispatcher; all commands are executed from here down.
-*/
+void glxSuspendClients(void)
+{
+    int i;
+
+    for (i = 1; i <= MAXCLIENTS; i++) {
+	if (__glXClients[i] == NULL || !__glXClients[i]->inUse)
+	    continue;
+
+	IgnoreClient(__glXClients[i]->client);
+    }
+
+    glxBlockClients = TRUE;
+}
+
+void glxResumeClients(void)
+{
+    __GLXcontext *cx, *next;
+    int i;
+
+    glxBlockClients = FALSE;
 
-/* I cried when I wrote this.  Damn you XAA! */
+    for (i = 1; i <= MAXCLIENTS; i++) {
+	if (__glXClients[i] == NULL || !__glXClients[i]->inUse)
+	    continue;
+
+	AttendClient(__glXClients[i]->client);
+    }
+
+    __glXleaveServer();
+    for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
+	next = cx->next;
+
+	cx->destroy(cx);
+    }
+    glxPendingDestroyContexts = NULL;
+    __glXenterServer();
+}
 
 static void
 __glXnopEnterServer(void)
@@ -412,14 +447,19 @@ void __glXsetEnterLeaveServerFuncs(void 
 
 void __glXenterServer(void)
 {
-  (*__glXenterServerFunc)();
+  glxServerLeaveCount--;
+
+  if (glxServerLeaveCount == 0)
+    (*__glXenterServerFunc)();
 }
 
 void __glXleaveServer(void)
 {
-  (*__glXleaveServerFunc)();
-}
+  if (glxServerLeaveCount == 0)
+    (*__glXleaveServerFunc)();
 
+  glxServerLeaveCount++;
+}
 
 /*
 ** Top level dispatcher; all commands are executed from here down.
@@ -472,6 +512,15 @@ static int __glXDispatch(ClientPtr clien
 	return __glXBadLargeRequest;
     }
 
+    /* If we're currently blocking GLX clients, just put this guy to
+     * sleep, reset the request and return. */
+    if (glxBlockClients) {
+	ResetCurrentRequest(client);
+	client->sequence--;
+	IgnoreClient(client);
+	return(client->noClientException);
+    }
+
     /*
     ** Use the opcode to index into the procedure table.
     */
@@ -482,12 +531,8 @@ static int __glXDispatch(ClientPtr clien
 
     __glXleaveServer();
 
-    inDispatch = True;
-
     retval = proc(cl, (GLbyte *) stuff);
 
-    inDispatch = False;
-
     __glXenterServer();
 
     return retval;
diff --git a/GL/glx/glxserver.h b/GL/glx/glxserver.h
index a41720f..df581b1 100644
--- a/GL/glx/glxserver.h
+++ b/GL/glx/glxserver.h
@@ -136,6 +136,9 @@ void __glXsetEnterLeaveServerFuncs(void 
 void __glXenterServer(void);
 void __glXleaveServer(void);
 
+void glxSuspendClients(void);
+void glxResumeClients(void);
+
 /*
 ** State kept per client.
 */
-- 
1.4.2

