summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c2042
1 files changed, 2042 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
new file mode 100644
index 00000000..8a1a61ff
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
@@ -0,0 +1,2042 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+#if 00 /*TEMPORARY*/
+#include <unistd.h>
+#include "cr_rand.h"
+#endif
+
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xmu/StdCmap.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_process.h"
+#include "renderspu.h"
+
+
+/*
+ * Stuff from MwmUtils.h
+ */
+typedef struct
+{
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} PropMotifWmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define MWM_HINTS_DECORATIONS (1L << 1)
+
+
+#define WINDOW_NAME window->title
+
+static Bool WindowExistsFlag;
+
+static int
+WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
+{
+ if (xerr->error_code == BadWindow)
+ {
+ WindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+static GLboolean
+WindowExists( Display *dpy, Window w )
+{
+ XWindowAttributes xwa;
+ int (*oldXErrorHandler)(Display *, XErrorEvent *);
+
+ WindowExistsFlag = GL_TRUE;
+ oldXErrorHandler = XSetErrorHandler(WindowExistsErrorHandler);
+ XGetWindowAttributes(dpy, w, &xwa); /* dummy request */
+ XSetErrorHandler(oldXErrorHandler);
+ return WindowExistsFlag;
+}
+
+static Colormap
+GetLUTColormap( Display *dpy, XVisualInfo *vi )
+{
+ int a;
+ XColor col;
+ Colormap cmap;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != DirectColor )
+ {
+ crError( "No support for non-DirectColor visuals with LUTs" );
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocAll );
+
+ for (a=0; a<256; a++)
+ {
+ col.red = render_spu.lut8[0][a]<<8;
+ col.green = col.blue = 0;
+ col.pixel = a<<16;
+ col.flags = DoRed;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.green = render_spu.lut8[1][a]<<8;
+ col.red = col.blue = 0;
+ col.pixel = a<<8;
+ col.flags = DoGreen;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.blue = render_spu.lut8[2][a]<<8;
+ col.red = col.green= 0;
+ col.pixel = a;
+ col.flags = DoBlue;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ return cmap;
+}
+
+static Colormap
+GetShareableColormap( Display *dpy, XVisualInfo *vi )
+{
+ Status status;
+ XStandardColormap *standardCmaps;
+ Colormap cmap;
+ int i, numCmaps;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != TrueColor )
+ {
+ crError( "No support for non-TrueColor visuals." );
+ }
+
+ status = XmuLookupStandardColormap( dpy, vi->screen, vi->visualid,
+ vi->depth, XA_RGB_DEFAULT_MAP,
+ False, True );
+
+ if ( status == 1 )
+ {
+ status = XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen),
+ &standardCmaps, &numCmaps,
+ XA_RGB_DEFAULT_MAP );
+ if ( status == 1 )
+ {
+ for (i = 0 ; i < numCmaps ; i++)
+ {
+ if (standardCmaps[i].visualid == vi->visualid)
+ {
+ cmap = standardCmaps[i].colormap;
+ XFree( standardCmaps);
+ return cmap;
+ }
+ }
+ }
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone );
+ return cmap;
+}
+
+
+static int
+WaitForMapNotify( Display *display, XEvent *event, char *arg )
+{
+ (void)display;
+ return ( event->type == MapNotify && event->xmap.window == (Window)arg );
+}
+
+
+/**
+ * Return the X Visual ID of the given window
+ */
+static int
+GetWindowVisualID( Display *dpy, Window w )
+{
+ XWindowAttributes attr;
+ int k = XGetWindowAttributes(dpy, w, &attr);
+ if (!k)
+ return -1;
+ return attr.visual->visualid;
+}
+
+
+/**
+ * Wrapper for glXGetConfig().
+ */
+static int
+Attrib( const VisualInfo *visual, int attrib )
+{
+ int value = 0;
+ render_spu.ws.glXGetConfig( visual->dpy, visual->visual, attrib, &value );
+ return value;
+}
+
+
+
+/**
+ * Find a visual with the specified attributes. If we fail, turn off an
+ * attribute (like multisample or stereo) and try again.
+ */
+static XVisualInfo *
+chooseVisualRetry( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ while (1) {
+ XVisualInfo *vis = crChooseVisual(&render_spu.ws, dpy, screen,
+ (GLboolean) render_spu.use_lut8,
+ visAttribs);
+ if (vis)
+ return vis;
+
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ visAttribs &= ~CR_MULTISAMPLE_BIT;
+ else if (visAttribs & CR_OVERLAY_BIT)
+ visAttribs &= ~CR_OVERLAY_BIT;
+ else if (visAttribs & CR_STEREO_BIT)
+ visAttribs &= ~CR_STEREO_BIT;
+ else if (visAttribs & CR_ACCUM_BIT)
+ visAttribs &= ~CR_ACCUM_BIT;
+ else if (visAttribs & CR_ALPHA_BIT)
+ visAttribs &= ~CR_ALPHA_BIT;
+ else
+ return NULL;
+ }
+}
+
+
+/**
+ * Get an FBconfig for the specified attributes
+ */
+#ifdef GLX_VERSION_1_3
+static GLXFBConfig
+chooseFBConfig( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ GLXFBConfig *fbconfig;
+ int attribs[1000], attrCount = 0, numConfigs;
+ int major, minor;
+
+ CRASSERT(visAttribs & CR_PBUFFER_BIT);
+
+ /* Make sure pbuffers are supported */
+ render_spu.ws.glXQueryVersion(dpy, &major, &minor);
+ if (major * 100 + minor < 103) {
+ crWarning("Render SPU: GLX %d.%d doesn't support pbuffers", major, minor);
+ return 0;
+ }
+
+ attribs[attrCount++] = GLX_DRAWABLE_TYPE;
+ attribs[attrCount++] = GLX_PBUFFER_BIT;
+
+ if (visAttribs & CR_RGB_BIT) {
+ attribs[attrCount++] = GLX_RENDER_TYPE;
+ attribs[attrCount++] = GLX_RGBA_BIT;
+ attribs[attrCount++] = GLX_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_DEPTH_BIT) {
+ attribs[attrCount++] = GLX_DEPTH_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_DOUBLE_BIT) {
+ attribs[attrCount++] = GLX_DOUBLEBUFFER;
+ attribs[attrCount++] = True;
+ }
+ else {
+ /* don't care */
+ }
+
+ if (visAttribs & CR_STENCIL_BIT) {
+ attribs[attrCount++] = GLX_STENCIL_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_ACCUM_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_MULTISAMPLE_BIT) {
+ attribs[attrCount++] = GLX_SAMPLE_BUFFERS_SGIS;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_SAMPLES_SGIS;
+ attribs[attrCount++] = 4;
+ }
+
+ if (visAttribs & CR_STEREO_BIT) {
+ attribs[attrCount++] = GLX_STEREO;
+ attribs[attrCount++] = 1;
+ }
+
+ /* terminate */
+ attribs[attrCount++] = 0;
+
+ fbconfig = render_spu.ws.glXChooseFBConfig(dpy, screen, attribs, &numConfigs);
+ if (!fbconfig || numConfigs == 0) {
+ /* no matches! */
+ return 0;
+ }
+ if (numConfigs == 1) {
+ /* one match */
+ return fbconfig[0];
+ }
+ else {
+ /* found several matches - try to find best one */
+ int i;
+
+ crDebug("Render SPU: glXChooseFBConfig found %d matches for visBits 0x%x",
+ numConfigs, visAttribs);
+ /* Skip/omit configs that have unneeded Z buffer or unneeded double
+ * buffering. Possible add other tests in the future.
+ */
+ for (i = 0; i < numConfigs; i++) {
+ int zBits, db;
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DEPTH_SIZE, &zBits);
+ if ((visAttribs & CR_DEPTH_BIT) == 0 && zBits > 0) {
+ /* omit fbconfig with unneeded Z */
+ continue;
+ }
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DOUBLEBUFFER, &db);
+ if ((visAttribs & CR_DOUBLE_BIT) == 0 && db) {
+ /* omit fbconfig with unneeded DB */
+ continue;
+ }
+
+ /* if we get here, use this config */
+ return fbconfig[i];
+ }
+
+ /* if we get here, we didn't find a better fbconfig */
+ return fbconfig[0];
+ }
+}
+#endif /* GLX_VERSION_1_3 */
+
+static const char * renderspuGetDisplayName()
+{
+ const char *dpyName;
+
+ if (render_spu.display_string[0])
+ dpyName = render_spu.display_string;
+ else
+ {
+ crWarning("Render SPU: no display..");
+ dpyName = NULL;
+ }
+ return dpyName;
+}
+
+static int renderspuWinCmdWinCreate(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdWinDestroy(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!crHashtableAllocRegisterKey(render_spu.windowTable, CR_RENDER_WINCMD_ID))
+ {
+ crError("CR_RENDER_WINCMD_ID %d is occupied already", CR_RENDER_WINCMD_ID);
+ return VERR_INVALID_STATE;
+ }
+
+ render_spu.pWinToInfoTable = crAllocHashtable();
+ if (render_spu.pWinToInfoTable)
+ {
+ dpyName = renderspuGetDisplayName();
+ if (dpyName)
+ {
+ GLboolean bRc = renderspuInitVisual(&render_spu.WinCmdVisual, dpyName, render_spu.default_visual);
+ if (bRc)
+ {
+ bRc = renderspuWinInitWithVisual(&render_spu.WinCmdWindow, &render_spu.WinCmdVisual, GL_FALSE, CR_RENDER_WINCMD_ID);
+ if (bRc)
+ {
+ XSelectInput(render_spu.WinCmdVisual.dpy, render_spu.WinCmdWindow.window, StructureNotifyMask);
+ render_spu.WinCmdAtom = XInternAtom(render_spu.WinCmdVisual.dpy, "VBoxWinCmd", False);
+ CRASSERT(render_spu.WinCmdAtom != None);
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crError("renderspuWinInitWithVisual failed");
+ }
+ /* there is no visual destroy impl currently
+ * @todo: implement */
+ }
+ else
+ {
+ crError("renderspuInitVisual failed");
+ }
+ }
+ else
+ {
+ crError("Render SPU: no display, aborting");
+ }
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ render_spu.pWinToInfoTable = NULL;
+ }
+ else
+ {
+ crError("crAllocHashtable failed");
+ }
+ return rc;
+}
+
+static void renderspuWinCmdTerm()
+{
+ /* the window is not in the table, this will just ensure the key is freed */
+ crHashtableDelete(render_spu.windowTable, CR_RENDER_WINCMD_ID, NULL);
+ renderspuWinCleanup(&render_spu.WinCmdWindow);
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ /* we do not have visual destroy functionality
+ * @todo implement */
+}
+
+
+static bool renderspuWinCmdProcess(CR_RENDER_WINCMD* pWinCmd)
+{
+ bool fExit = false;
+ /* process commands */
+ switch (pWinCmd->enmCmd)
+ {
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE:
+ crHashtableAdd(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, pWinCmd->pWindow);
+ XSelectInput(render_spu.WinCmdVisual.dpy, pWinCmd->pWindow->window, ExposureMask);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY:
+ crHashtableDelete(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, NULL);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_NOP:
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_EXIT:
+ renderspuWinCmdTerm();
+ pWinCmd->rc = VINF_SUCCESS;
+ fExit = true;
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_CREATE:
+ pWinCmd->rc = renderspuWinCmdWinCreate(pWinCmd->pWindow);
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_DESTROY:
+ pWinCmd->rc = renderspuWinCmdWinDestroy(pWinCmd->pWindow);
+ break;
+ default:
+ crError("unknown WinCmd command! %d", pWinCmd->enmCmd);
+ pWinCmd->rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+ return fExit;
+}
+
+static DECLCALLBACK(int) renderspuWinCmdThreadProc(RTTHREAD ThreadSelf, void *pvUser)
+{
+ int rc;
+ bool fExit = false;
+ crDebug("RenderSPU: Window thread started (%x)", crThreadID());
+
+ rc = renderspuWinCmdInit();
+
+ /* notify the main cmd thread that we have started */
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+
+ if (!RT_SUCCESS(rc))
+ {
+ CRASSERT(!render_spu.pWinToInfoTable);
+ return rc;
+ }
+
+ do
+ {
+ XEvent event;
+ XNextEvent(render_spu.WinCmdVisual.dpy, &event);
+
+ switch (event.type)
+ {
+ case ClientMessage:
+ {
+ CRASSERT(event.xclient.window == render_spu.WinCmdWindow.window);
+ if (event.xclient.window == render_spu.WinCmdWindow.window)
+ {
+ if (render_spu.WinCmdAtom == event.xclient.message_type)
+ {
+ CR_RENDER_WINCMD *pWinCmd;
+ memcpy(&pWinCmd, event.xclient.data.b, sizeof (pWinCmd));
+ fExit = renderspuWinCmdProcess(pWinCmd);
+ }
+ }
+
+ break;
+ }
+ case Expose:
+ {
+ if (!event.xexpose.count)
+ {
+ WindowInfo *pWindow = (WindowInfo*)crHashtableSearch(render_spu.pWinToInfoTable, event.xexpose.window);
+ if (pWindow)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pCompositor;
+
+ pCompositor = renderspuVBoxCompositorAcquire(pWindow);
+ if (pCompositor)
+ {
+ renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 0, false);
+ renderspuVBoxCompositorRelease(pWindow);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } while (!fExit);
+
+ return 0;
+}
+
+static int renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE enmCmd, WindowInfo *pWindow)
+{
+ Status status;
+ XEvent event;
+ CR_RENDER_WINCMD WinCmd, *pWinCmd;
+ int rc;
+
+ pWinCmd = &WinCmd;
+ pWinCmd->enmCmd = enmCmd;
+ pWinCmd->rc = VERR_GENERAL_FAILURE;
+ pWinCmd->pWindow = pWindow;
+
+ memset(&event, 0, sizeof (event));
+ event.type = ClientMessage;
+ event.xclient.window = render_spu.WinCmdWindow.window;
+ event.xclient.message_type = render_spu.WinCmdAtom;
+ event.xclient.format = 8;
+ memcpy(event.xclient.data.b, &pWinCmd, sizeof (pWinCmd));
+
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, StructureNotifyMask, &event);
+ if (!status)
+ {
+ Assert(0);
+ crWarning("XSendEvent returned null");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ XFlush(render_spu.pCommunicationDisplay);
+ rc = RTSemEventWaitNoResume(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTSemEventWaitNoResume failed rc %d", rc);
+ return rc;
+ }
+ return pWinCmd->rc;
+}
+
+int renderspu_SystemInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!render_spu.use_glxchoosevisual) {
+ /* sometimes want to set this option with ATI drivers */
+ render_spu.ws.glXChooseVisual = NULL;
+ }
+
+ /* setup communication display connection */
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("no display name, aborting");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ render_spu.pCommunicationDisplay = XOpenDisplay(dpyName);
+ if (!render_spu.pCommunicationDisplay)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( render_spu.pCommunicationDisplay, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ rc = RTSemEventCreate(&render_spu.hWinCmdCompleteEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreate(&render_spu.hWinCmdThread, renderspuWinCmdThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxCrWinCmd");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventWait(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crWarning("RTSemEventWait failed rc %d", rc);
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ }
+ else
+ {
+ crWarning("RTThreadCreate failed rc %d", rc);
+ }
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ }
+ else
+ {
+ crWarning("RTSemEventCreate failed rc %d", rc);
+ }
+
+ return rc;
+}
+
+int renderspu_SystemTerm()
+{
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_EXIT, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("renderspuWinCmdSubmit EXIT failed rc %d", rc);
+ return rc;
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ return VINF_SUCCESS;
+}
+
+GLboolean
+renderspu_SystemInitVisual( VisualInfo *visual )
+{
+ const char *dpyName;
+ int screen;
+
+ CRASSERT(visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ /* A dummy visual - being non null is enough. */
+ visual->visual =(XVisualInfo *) "os";
+ return GL_TRUE;
+ }
+#endif
+
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("Render SPU: no display, aborting");
+ return GL_FALSE;
+ }
+
+
+ crInfo("Render SPU: Opening display %s", dpyName);
+
+ if (dpyName &&
+ (crStrncmp(dpyName, "localhost:11", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:12", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:13", 12) == 0)) {
+ /* Issue both debug and warning messages to make sure the
+ * message gets noticed!
+ */
+ crDebug("Render SPU: display string looks like a proxy X server!");
+ crDebug("Render SPU: This is usually a problem!");
+ crWarning("Render SPU: display string looks like a proxy X server!");
+ crWarning("Render SPU: This is usually a problem!");
+ }
+
+ visual->dpy = XOpenDisplay(dpyName);
+ if (!visual->dpy)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return GL_FALSE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( visual->dpy, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", visual->displayName );
+ return GL_FALSE;
+ }
+
+ screen = DefaultScreen(visual->dpy);
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ visual->fbconfig = chooseFBConfig(visual->dpy, screen, visual->visAttribs);
+ if (!visual->fbconfig) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning( "Render SPU: Display %s doesn't have the necessary fbconfig: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+ else
+#endif /* GLX_VERSION_1_3 */
+ {
+ visual->visual = chooseVisualRetry(visual->dpy, screen, visual->visAttribs);
+ if (!visual->visual) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning("Render SPU: Display %s doesn't have the necessary visual: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+
+ if ( render_spu.sync )
+ {
+ crDebug( "Render SPU: Turning on XSynchronize" );
+ XSynchronize( visual->dpy, True );
+ }
+
+ if (visual->visual) {
+ crDebug( "Render SPU: Choose visual id=0x%x: RGBA=(%d,%d,%d,%d) Z=%d"
+ " stencil=%d double=%d stereo=%d accum=(%d,%d,%d,%d)",
+ (int) visual->visual->visualid,
+ Attrib( visual, GLX_RED_SIZE ),
+ Attrib( visual, GLX_GREEN_SIZE ),
+ Attrib( visual, GLX_BLUE_SIZE ),
+ Attrib( visual, GLX_ALPHA_SIZE ),
+ Attrib( visual, GLX_DEPTH_SIZE ),
+ Attrib( visual, GLX_STENCIL_SIZE ),
+ Attrib( visual, GLX_DOUBLEBUFFER ),
+ Attrib( visual, GLX_STEREO ),
+ Attrib( visual, GLX_ACCUM_RED_SIZE ),
+ Attrib( visual, GLX_ACCUM_GREEN_SIZE ),
+ Attrib( visual, GLX_ACCUM_BLUE_SIZE ),
+ Attrib( visual, GLX_ACCUM_ALPHA_SIZE )
+ );
+ }
+ else if (visual->fbconfig) {
+ int id;
+ render_spu.ws.glXGetFBConfigAttrib(visual->dpy, visual->fbconfig,
+ GLX_FBCONFIG_ID, &id);
+ crDebug("Render SPU: Chose FBConfig 0x%x, visBits=0x%x",
+ id, visual->visAttribs);
+ }
+
+ return GL_TRUE;
+}
+
+
+/*
+ * Add a GLX window to a swap group for inter-machine SwapBuffer
+ * synchronization.
+ * Only supported on NVIDIA Quadro 3000G hardware.
+ */
+static void
+JoinSwapGroup(Display *dpy, int screen, Window window,
+ GLuint group, GLuint barrier)
+{
+ GLuint maxGroups, maxBarriers;
+ const char *ext;
+ Bool b;
+
+ /*
+ * XXX maybe query glXGetClientString() instead???
+ */
+ ext = render_spu.ws.glXQueryExtensionsString(dpy, screen);
+
+ if (!crStrstr(ext, "GLX_NV_swap_group") ||
+ !render_spu.ws.glXQueryMaxSwapGroupsNV ||
+ !render_spu.ws.glXJoinSwapGroupNV ||
+ !render_spu.ws.glXBindSwapBarrierNV) {
+ crWarning("Render SPU: nv_swap_group is set but GLX_NV_swap_group is not supported on this system!");
+ return;
+ }
+
+ b = render_spu.ws.glXQueryMaxSwapGroupsNV(dpy, screen,
+ &maxGroups, &maxBarriers);
+ if (!b)
+ crWarning("Render SPU: call to glXQueryMaxSwapGroupsNV() failed!");
+
+ if (group >= maxGroups) {
+ crWarning("Render SPU: nv_swap_group too large (%d > %d)",
+ group, (int) maxGroups);
+ return;
+ }
+ crDebug("Render SPU: max swap groups = %d, max barriers = %d",
+ maxGroups, maxBarriers);
+
+ /* add this window to the swap group */
+ b = render_spu.ws.glXJoinSwapGroupNV(dpy, window, group);
+ if (!b) {
+ crWarning("Render SPU: call to glXJoinSwapGroupNV() failed!");
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXJoinSwapGroupNV() worked!");
+ }
+
+ /* ... and bind window to barrier of same ID */
+ b = render_spu.ws.glXBindSwapBarrierNV(dpy, group, barrier);
+ if (!b) {
+ crWarning("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) failed!", group, barrier);
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) worked!", group, barrier);
+ }
+
+ crDebug("Render SPU: window has joined swap group %d", group);
+}
+
+
+
+static GLboolean
+createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ Display *dpy;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XSizeHints hints = {0};
+ XEvent event;
+ XTextProperty text_prop;
+ XClassHint *class_hints = NULL;
+ Window parent;
+ char *name;
+ unsigned long flags;
+ unsigned int vncWin;
+
+ CRASSERT(visual);
+ window->visual = visual;
+ window->nativeWindow = 0;
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return GL_TRUE;
+#endif
+
+ dpy = visual->dpy;
+
+ if ( render_spu.use_L2 )
+ {
+ crWarning( "Render SPU: Going fullscreen because we think we're using Lightning-2." );
+ render_spu.fullscreen = 1;
+ }
+
+ /*
+ * Query screen size if we're going full-screen
+ */
+ if ( render_spu.fullscreen )
+ {
+ XWindowAttributes xwa;
+ Window root_window;
+
+ /* disable the screensaver */
+ XSetScreenSaver( dpy, 0, 0, PreferBlanking, AllowExposures );
+ crDebug( "Render SPU: Just turned off the screensaver" );
+
+ /* Figure out how big the screen is, and make the window that size */
+ root_window = DefaultRootWindow( dpy );
+ XGetWindowAttributes( dpy, root_window, &xwa );
+
+ crDebug( "Render SPU: root window size: %d x %d", xwa.width, xwa.height );
+
+ window->x = 0;
+ window->y = 0;
+ window->BltInfo.width = xwa.width;
+ window->BltInfo.height = xwa.height;
+ }
+
+ /* i've changed default window size to be 0,0 but X doesn't like it */
+ /*CRASSERT(window->BltInfo.width >= 1);
+ CRASSERT(window->BltInfo.height >= 1);*/
+ if (window->BltInfo.width < 1) window->BltInfo.width = 1;
+ if (window->BltInfo.height < 1) window->BltInfo.height = 1;
+
+ /*
+ * Get a colormap.
+ */
+ if (render_spu.use_lut8)
+ cmap = GetLUTColormap( dpy, visual->visual );
+ else
+ cmap = GetShareableColormap( dpy, visual->visual );
+ if ( !cmap ) {
+ crError( "Render SPU: Unable to get a colormap!" );
+ return GL_FALSE;
+ }
+
+ /* destroy existing window if there is one */
+ if (window->window) {
+ XDestroyWindow(dpy, window->window);
+ }
+
+ /*
+ * Create the window
+ *
+ * POSSIBLE OPTIMIZATION:
+ * If we're using the render_to_app_window or render_to_crut_window option
+ * (or DMX) we may never actually use this X window. So we could perhaps
+ * delay its creation until glXMakeCurrent is called. With NVIDIA's OpenGL
+ * driver, creating a lot of GLX windows can eat up a lot of VRAM and lead
+ * to slow, software-fallback rendering. Apps that use render_to_app_window,
+ * etc should set the default window size very small to avoid this.
+ * See dmx.conf for example.
+ */
+ swa.colormap = cmap;
+ swa.border_pixel = 0;
+ swa.event_mask = ExposureMask | StructureNotifyMask;
+ swa.override_redirect = 1;
+
+ flags = CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ /*
+ * We pass the VNC's desktop windowID via an environment variable.
+ * If we don't find one, we're not on a 3D-capable vncviewer, or
+ * if we do find one, then create the renderspu subwindow as a
+ * child of the vncviewer's desktop window.
+ *
+ * This is purely for the replicateSPU.
+ *
+ * NOTE: This is crufty, and will do for now. FIXME.
+ */
+ vncWin = crStrToInt( crGetenv("CRVNCWINDOW") );
+ if (vncWin)
+ parent = (Window) vncWin;
+ else
+ parent = RootWindow(dpy, visual->visual->screen);
+
+ if (render_spu_parent_window_id>0)
+ {
+ crDebug("Render SPU: VBox parent window_id is: %x", render_spu_parent_window_id);
+ window->window = XCreateWindow(dpy, render_spu_parent_window_id,
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+ else
+ {
+ /* This should happen only at the call from crVBoxServerInit. At this point we don't
+ * know render_spu_parent_window_id yet, nor we need it for default window which is hidden.
+ */
+
+ crDebug("Render SPU: Creating global window, parent: %x", RootWindow(dpy, visual->visual->screen));
+ window->window = XCreateWindow(dpy, RootWindow(dpy, visual->visual->screen),
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+
+ if (!window->window) {
+ crWarning( "Render SPU: unable to create window" );
+ return GL_FALSE;
+ }
+
+ crDebug( "Render SPU: Created window 0x%x on display %s, Xvisual 0x%x",
+ (int) window->window,
+ DisplayString(visual->dpy),
+ (int) visual->visual->visual->visualid /* yikes */
+ );
+
+ if (render_spu.fullscreen || render_spu.borderless)
+ {
+ /* Disable border/decorations with an MWM property (observed by most
+ * modern window managers.
+ */
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = 0; /* Turn off all decorations */
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (prop) {
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+ XChangeProperty( dpy, window->window, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+ }
+ }
+
+ /* Make a clear cursor to get rid of the monitor cursor */
+ if ( render_spu.fullscreen )
+ {
+ Pixmap pixmap;
+ Cursor cursor;
+ XColor colour;
+ char clearByte = 0;
+
+ /* AdB - Only bother to create a 1x1 cursor (byte) */
+ pixmap = XCreatePixmapFromBitmapData(dpy, window->window, &clearByte,
+ 1, 1, 1, 0, 1);
+ if(!pixmap){
+ crWarning("Unable to create clear cursor pixmap");
+ return GL_FALSE;
+ }
+
+ cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &colour, &colour, 0, 0);
+ if(!cursor){
+ crWarning("Unable to create clear cursor from zero byte pixmap");
+ return GL_FALSE;
+ }
+ XDefineCursor(dpy, window->window, cursor);
+ XFreePixmap(dpy, pixmap);
+ }
+
+ hints.x = window->x;
+ hints.y = window->y;
+ hints.width = window->BltInfo.width;
+ hints.height = window->BltInfo.height;
+ hints.min_width = hints.width;
+ hints.min_height = hints.height;
+ hints.max_width = hints.width;
+ hints.max_height = hints.height;
+ if (render_spu.resizable)
+ hints.flags = USPosition | USSize;
+ else
+ hints.flags = USPosition | USSize | PMinSize | PMaxSize;
+ XSetStandardProperties( dpy, window->window,
+ WINDOW_NAME, WINDOW_NAME,
+ None, NULL, 0, &hints );
+
+ /* New item! This is needed so that the sgimouse server can find
+ * the crDebug window.
+ */
+ name = WINDOW_NAME;
+ XStringListToTextProperty( &name, 1, &text_prop );
+ XSetWMName( dpy, window->window, &text_prop );
+
+ /* Set window name, resource class */
+ class_hints = XAllocClassHint( );
+ class_hints->res_name = crStrdup( "foo" );
+ class_hints->res_class = crStrdup( "Chromium" );
+ XSetClassHint( dpy, window->window, class_hints );
+ crFree( class_hints->res_name );
+ crFree( class_hints->res_class );
+ XFree( class_hints );
+
+ if (showIt) {
+ XMapWindow( dpy, window->window );
+ XIfEvent( dpy, &event, WaitForMapNotify,
+ (char *) window->window );
+ }
+
+ if ((window->visual->visAttribs & CR_DOUBLE_BIT) && render_spu.nvSwapGroup) {
+ /* NOTE:
+ * If this SPU creates N windows we don't want to gang the N windows
+ * together!
+ * By adding the window ID to the nvSwapGroup ID we can be sure each
+ * app window is in a separate swap group while all the back-end windows
+ * which form a mural are in the same swap group.
+ */
+ GLuint group = 0; /*render_spu.nvSwapGroup + window->BltInfo.Base.id;*/
+ GLuint barrier = 0;
+ JoinSwapGroup(dpy, visual->visual->screen, window->window, group, barrier);
+ }
+
+ /*
+ * End GLX code
+ */
+ crDebug( "Render SPU: actual window x, y, width, height: %d, %d, %d, %d",
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height );
+
+ XSync(dpy, 0);
+
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE, window);
+ AssertRC(rc);
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+createPBuffer( VisualInfo *visual, WindowInfo *window )
+{
+ window->visual = visual;
+ window->x = 0;
+ window->y = 0;
+ window->nativeWindow = 0;
+
+ CRASSERT(window->BltInfo.width > 0);
+ CRASSERT(window->BltInfo.height > 0);
+
+#ifdef GLX_VERSION_1_3
+ {
+ int attribs[100], i = 0, w, h;
+ CRASSERT(visual->fbconfig);
+ w = window->BltInfo.width;
+ h = window->BltInfo.height;
+ attribs[i++] = GLX_PRESERVED_CONTENTS;
+ attribs[i++] = True;
+ attribs[i++] = GLX_PBUFFER_WIDTH;
+ attribs[i++] = w;
+ attribs[i++] = GLX_PBUFFER_HEIGHT;
+ attribs[i++] = h;
+ attribs[i++] = 0; /* terminator */
+ window->window = render_spu.ws.glXCreatePbuffer(visual->dpy,
+ visual->fbconfig, attribs);
+ if (window->window) {
+ crDebug("Render SPU: Allocated %d x %d pbuffer", w, h);
+ return GL_TRUE;
+ }
+ else {
+ crWarning("Render SPU: Failed to allocate %d x %d pbuffer", w, h);
+ return GL_FALSE;
+ }
+ }
+#endif /* GLX_VERSION_1_3 */
+ return GL_FALSE;
+}
+
+
+GLboolean
+renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ window->BltInfo.width = render_spu.defaultWidth;
+ window->BltInfo.height = render_spu.defaultHeight;
+ return createPBuffer(visual, window);
+ }
+ else {
+ return createWindow(visual, showIt, window);
+ }
+}
+
+GLboolean
+renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ return renderspu_SystemCreateWindow(visual, showIt, window);
+}
+
+void
+renderspu_SystemDestroyWindow( WindowInfo *window )
+{
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ crFree(window->buffer);
+ window->buffer = NULL;
+ }
+ else
+#endif
+ {
+ if (window->visual->visAttribs & CR_PBUFFER_BIT) {
+#ifdef GLX_VERSION_1_3
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+#endif
+ }
+ else {
+ /* The value window->nativeWindow will only be non-NULL if the
+ * render_to_app_window option is set to true. In this case, we
+ * don't want to do anything, since we're not responsible for this
+ * window. I know...personal responsibility and all...
+ */
+ if (!window->nativeWindow) {
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY, window);
+ AssertRC(rc);
+ }
+ XDestroyWindow(window->visual->dpy, window->window);
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ }
+ window->visual = NULL;
+ window->window = 0;
+}
+
+
+GLboolean
+renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
+{
+ Bool is_direct;
+ GLXContext sharedSystemContext = NULL;
+
+ CRASSERT(visual);
+ CRASSERT(context);
+
+ context->visual = visual;
+
+ if (sharedContext != NULL) {
+ sharedSystemContext = sharedContext->context;
+ }
+
+
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ context->context = (GLXContext) render_spu.OSMesaCreateContext(OSMESA_RGB, 0);
+ if (context->context)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+ }
+#endif
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ context->context = render_spu.ws.glXCreateNewContext( visual->dpy,
+ visual->fbconfig,
+ GLX_RGBA_TYPE,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ else
+#endif
+ {
+ context->context = render_spu.ws.glXCreateContext( visual->dpy,
+ visual->visual,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ if (!context->context) {
+ crError( "Render SPU: Couldn't create rendering context" );
+ return GL_FALSE;
+ }
+
+ is_direct = render_spu.ws.glXIsDirect( visual->dpy, context->context );
+ if (visual->visual)
+ crDebug("Render SPU: Created %s context (%d) on display %s for visAttribs 0x%x",
+ is_direct ? "DIRECT" : "INDIRECT",
+ context->BltInfo.Base.id,
+ DisplayString(visual->dpy),
+ visual->visAttribs);
+
+ if ( render_spu.force_direct && !is_direct )
+ {
+ crError( "Render SPU: Direct rendering not possible." );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+#define USE_GLX_COPYCONTEXT 0
+
+#if !USE_GLX_COPYCONTEXT
+
+/**
+ * Unfortunately, glXCopyContext() is broken sometimes (NVIDIA 76.76 driver).
+ * This bit of code gets and sets GL state we need to copy between contexts.
+ */
+struct saved_state
+{
+ /* XXX depending on the app, more state may be needed here */
+ GLboolean Lighting;
+ GLboolean LightEnabled[8];
+ GLfloat LightPos[8][4];
+ GLfloat LightAmbient[8][4];
+ GLfloat LightDiffuse[8][4];
+ GLfloat LightSpecular[8][4];
+ GLboolean DepthTest;
+};
+
+static struct saved_state SavedState;
+
+static void
+get_state(struct saved_state *s)
+{
+ int i;
+
+ s->Lighting = render_spu.self.IsEnabled(GL_LIGHTING);
+ for (i = 0; i < 8; i++) {
+ s->LightEnabled[i] = render_spu.self.IsEnabled(GL_LIGHT0 + i);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ s->DepthTest = render_spu.self.IsEnabled(GL_DEPTH_TEST);
+}
+
+static void
+set_state(const struct saved_state *s)
+{
+ int i;
+
+ if (s->Lighting) {
+ render_spu.self.Enable(GL_LIGHTING);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHTING);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (s->LightEnabled[i]) {
+ render_spu.self.Enable(GL_LIGHT0 + i);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHT0 + i);
+ }
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ if (s->DepthTest)
+ render_spu.self.Enable(GL_DEPTH_TEST);
+ else
+ render_spu.self.Disable(GL_DEPTH_TEST);
+}
+
+#endif /* !USE_GLX_COPYCONTEXT */
+
+/**
+ * Recreate the GLX context for ContextInfo. The new context will use the
+ * visual specified by newVisualID.
+ */
+static void
+renderspu_RecreateContext( ContextInfo *context, int newVisualID )
+{
+ XVisualInfo templateVis, *vis;
+ long templateFlags;
+ int screen = 0, count;
+ GLXContext oldContext = context->context;
+
+ templateFlags = VisualScreenMask | VisualIDMask;
+ templateVis.screen = screen;
+ templateVis.visualid = newVisualID;
+ vis = XGetVisualInfo(context->visual->dpy, templateFlags, &templateVis, &count);
+ CRASSERT(vis);
+ if (!vis)
+ return;
+
+ /* create new context */
+ crDebug("Render SPU: Creating new GLX context with visual 0x%x", newVisualID);
+ context->context = render_spu.ws.glXCreateContext(context->visual->dpy,
+ vis, NULL,
+ render_spu.try_direct);
+ CRASSERT(context->context);
+
+#if USE_GLX_COPYCONTEXT
+ /* copy old context state to new context */
+ render_spu.ws.glXCopyContext(context->visual->dpy,
+ oldContext, context->context, ~0);
+ crDebug("Render SPU: Done copying context state");
+#endif
+
+ /* destroy old context */
+ render_spu.ws.glXDestroyContext(context->visual->dpy, oldContext);
+
+ context->visual->visual = vis;
+}
+
+
+void
+renderspu_SystemDestroyContext( ContextInfo *context )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ render_spu.OSMesaDestroyContext( (OSMesaContext) context->context );
+ }
+ else
+#endif
+ {
+#if 0
+ /* XXX disable for now - causes segfaults w/ NVIDIA's driver */
+ render_spu.ws.glXDestroyContext( context->visual->dpy, context->context );
+#endif
+ }
+ context->visual = NULL;
+ context->context = 0;
+}
+
+
+#ifdef USE_OSMESA
+static void
+check_buffer_size( WindowInfo *window )
+{
+ if (window->BltInfo.width != window->in_buffer_width
+ || window->BltInfo.height != window->in_buffer_height
+ || ! window->buffer) {
+ crFree(window->buffer);
+
+ window->buffer = crCalloc(window->BltInfo.width * window->BltInfo.height
+ * 4 * sizeof (GLubyte));
+
+ window->in_buffer_width = window->BltInfo.width;
+ window->in_buffer_height = window->BltInfo.height;
+
+ crDebug("Render SPU: dimensions changed to %d x %d", window->BltInfo.width, window->BltInfo.height);
+ }
+}
+#endif
+
+
+void
+renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow,
+ ContextInfo *context )
+{
+ Bool b;
+
+ CRASSERT(render_spu.ws.glXMakeCurrent);
+
+ /*crDebug("%s nativeWindow=0x%x", __FUNCTION__, (int) nativeWindow);*/
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ check_buffer_size(window);
+ render_spu.OSMesaMakeCurrent( (OSMesaContext) context->context,
+ window->buffer, GL_UNSIGNED_BYTE,
+ window->BltInfo.width, window->BltInfo.height);
+ return;
+ }
+#endif
+
+ nativeWindow = 0;
+
+ if (window && context) {
+ window->appWindow = nativeWindow;
+
+ if (window->visual != context->visual) {
+ crDebug("Render SPU: MakeCurrent visual mismatch (win(%d) bits:0x%x != ctx(%d) bits:0x%x); remaking window.",
+ window->BltInfo.Base.id, window->visual->visAttribs,
+ context->BltInfo.Base.id, context->visual->visAttribs);
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+#ifndef SOLARIS_9_X_BUG
+ /*
+ I'm having some really weird issues if I destroy this window
+ when I'm using the version of sunX that comes with Solaris 9.
+ Subsiquent glX calls return GLXBadCurrentWindow error.
+
+ This is an issue even when running Linux version and using
+ the Solaris 9 sunX as a display.
+ -- jw
+
+ jw: we might have to call glXMakeCurrent(dpy, 0, 0) to unbind
+ the context from the window before destroying it. -Brian
+ */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy, 0, 0);
+ renderspu_SystemDestroyWindow( window );
+#endif
+ renderspu_SystemCreateWindow( context->visual, window->visible, window );
+ /*
+ crError("In renderspu_SystemMakeCurrent() window and context"
+ " weren't created with same visual!");
+ */
+ }
+
+ CRASSERT(context->context);
+
+#if 0
+ if (render_spu.render_to_crut_window) {
+ if (render_spu.crut_drawable == 0) {
+ /* We don't know the X drawable ID yet. Ask mothership for it. */
+ char response[8096];
+ CRConnection *conn = crMothershipConnect();
+ if (!conn)
+ {
+ crError("Couldn't connect to the mothership to get CRUT drawable-- "
+ "I have no idea what to do!");
+ }
+ crMothershipGetParam( conn, "crut_drawable", response );
+ render_spu.crut_drawable = crStrToInt(response);
+ crMothershipDisconnect(conn);
+
+ crDebug("Render SPU: using CRUT drawable: 0x%x",
+ render_spu.crut_drawable);
+ if (!render_spu.crut_drawable) {
+ crDebug("Render SPU: Crut drawable 0 is invalid");
+ /* Continue with nativeWindow = 0; we'll render to the window that
+ * we (the Render SPU) previously created.
+ */
+ }
+ }
+
+ nativeWindow = render_spu.crut_drawable;
+ }
+#endif
+
+ if ((render_spu.render_to_crut_window || render_spu.render_to_app_window)
+ && nativeWindow)
+ {
+ /* We're about to bind the rendering context to a window that we
+ * (the Render SPU) did not create. The window was created by the
+ * application or the CRUT server.
+ * Make sure the window ID is valid and that the window's X visual is
+ * the same as the rendering context's.
+ */
+ if (WindowExists(window->visual->dpy, nativeWindow))
+ {
+ int vid = GetWindowVisualID(window->visual->dpy, nativeWindow);
+ GLboolean recreated = GL_FALSE;
+
+ /* check that the window's visual and context's visual match */
+ if (vid != (int) context->visual->visual->visualid) {
+ crWarning("Render SPU: Can't bind context %d to CRUT/native window "
+ "0x%x because of different X visuals (0x%x != 0x%x)!",
+ context->BltInfo.Base.id, (int) nativeWindow,
+ vid, (int) context->visual->visual->visualid);
+ crWarning("Render SPU: Trying to recreate GLX context to match.");
+ /* Try to recreate the GLX context so that it uses the same
+ * GLX visual as the window.
+ */
+#if !USE_GLX_COPYCONTEXT
+ if (context->everCurrent) {
+ get_state(&SavedState);
+ }
+#endif
+ renderspu_RecreateContext(context, vid);
+ recreated = GL_TRUE;
+ }
+
+ /* OK, this should work */
+ window->nativeWindow = (Window) nativeWindow;
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->nativeWindow,
+ context->context );
+ CRASSERT(b);
+#if !USE_GLX_COPYCONTEXT
+ if (recreated) {
+ set_state(&SavedState);
+ }
+#endif
+ }
+ else
+ {
+ crWarning("Render SPU: render_to_app/crut_window option is set but "
+ "the window ID 0x%x is invalid on the display named %s",
+ (unsigned int) nativeWindow,
+ DisplayString(window->visual->dpy));
+ CRASSERT(window->window);
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ CRASSERT(b);
+ }
+ }
+ else
+ {
+ /* This is the normal case - rendering to the render SPU's own window */
+ CRASSERT(window->window);
+#if 0
+ crDebug("calling glXMakecurrent(%p, 0x%x, 0x%x)",
+ window->visual->dpy,
+ (int) window->window, (int) context->context );
+#endif
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, 0x%x, %p) failed! (winId %d, ctxId %d)",
+ window->visual->dpy,
+ (int) window->window, (void *) context->context,
+ window->BltInfo.Base.id, context->BltInfo.Base.id );
+ }
+ /*CRASSERT(b);*/
+ }
+
+ /* XXX this is a total hack to work around an NVIDIA driver bug */
+#if 0
+ if (render_spu.self.GetFloatv && context->haveWindowPosARB) {
+ GLfloat f[4];
+ render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
+ if (!window->everCurrent || f[1] < 0.0) {
+ crDebug("Render SPU: Resetting raster pos");
+ render_spu.self.WindowPos2iARB(0, 0);
+ }
+ }
+#endif
+ }
+ else
+ {
+ GET_CONTEXT(pCurCtx);
+ if (pCurCtx)
+ {
+ b = render_spu.ws.glXMakeCurrent( pCurCtx->currentWindow->visual->dpy, None, NULL);
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, None, NULL) failed!", pCurCtx->currentWindow->visual->dpy);
+ }
+ }
+
+ }
+}
+
+
+/**
+ * Set window (or pbuffer) size.
+ */
+void
+renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ check_buffer_size(window);
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ /* resizing a pbuffer */
+ if (render_spu.pbufferWidth != 0 || render_spu.pbufferHeight != 0) {
+ /* size limit check */
+ if (w > render_spu.pbufferWidth || h > render_spu.pbufferHeight) {
+ crWarning("Render SPU: Request for %d x %d pbuffer is larger than "
+ "the configured size of %d x %d. ('pbuffer_size')",
+ w, h, render_spu.pbufferWidth, render_spu.pbufferHeight);
+ return;
+ }
+ /*
+ * If the requested new pbuffer size is greater than 1/2 the size of
+ * the max pbuffer, just use the max pbuffer size. This helps avoid
+ * problems with VRAM memory fragmentation. If we run out of VRAM
+ * for pbuffers, some drivers revert to software rendering. We want
+ * to avoid that!
+ */
+ if (w * h >= render_spu.pbufferWidth * render_spu.pbufferHeight / 2) {
+ /* increase the dimensions to the max pbuffer size now */
+ w = render_spu.pbufferWidth;
+ h = render_spu.pbufferHeight;
+ }
+ }
+
+ if (window->BltInfo.width != w || window->BltInfo.height != h) {
+ /* Only resize if the new dimensions really are different */
+#ifdef CHROMIUM_THREADSAFE
+ ContextInfo *currentContext = (ContextInfo *) crGetTSD(&_RenderTSD);
+#else
+ ContextInfo *currentContext = render_spu.currentContext;
+#endif
+ /* Can't resize pbuffers, so destroy it and make a new one */
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ crDebug("Render SPU: Creating new %d x %d PBuffer (id=%d)",
+ w, h, window->BltInfo.Base.id);
+ if (!createPBuffer(window->visual, window)) {
+ crWarning("Render SPU: Unable to create PBuffer (out of VRAM?)!");
+ }
+ else if (currentContext && currentContext->currentWindow == window) {
+ /* Determine if we need to bind the current context to new pbuffer */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy,
+ window->window,
+ currentContext->context );
+ }
+ }
+ }
+ else {
+ if (!w || !h)
+ {
+ /* X can not handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_FALSE );
+ }
+ return;
+ }
+ /* Resize ordinary X window */
+ /*
+ * This is ugly, but it seems to be the only thing that works.
+ * Basically, XResizeWindow() doesn't seem to always take effect
+ * immediately.
+ * Even after an XSync(), the GetWindowAttributes() call will sometimes
+ * return the old window size. So, we use a loop to repeat the window
+ * resize until it seems to take effect.
+ */
+ int attempt;
+ crDebug("Render SPU: XResizeWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, w, h);
+ XResizeWindow(window->visual->dpy, window->window, w, h);
+ XSync(window->visual->dpy, 0);
+
+ if (!window->BltInfo.width || !window->BltInfo.height)
+ {
+ /* we have hidden the window instead of sizing it to (0;0) since X is unable to handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_TRUE );
+ return;
+ }
+ }
+#if 0
+ for (attempt = 0; attempt < 3; attempt++) { /* try three times max */
+ XWindowAttributes attribs;
+ /* Now, query the window size */
+ XGetWindowAttributes(window->visual->dpy, window->window, &attribs);
+ if (attribs.width == w && attribs.height == h)
+ break;
+ /* sleep for a millisecond and try again */
+ crMsleep(1);
+ }
+#endif
+ }
+}
+
+
+void
+renderspu_SystemGetWindowGeometry( WindowInfo *window,
+ GLint *x, GLint *y, GLint *w, GLint *h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ *x = 0;
+ *y = 0;
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ }
+ else
+ {
+ Window xw, child, root;
+ unsigned int width, height, bw, d;
+ int rx, ry;
+
+ if ((render_spu.render_to_app_window || render_spu.render_to_crut_window)
+ && window->nativeWindow) {
+ xw = window->nativeWindow;
+ }
+ else {
+ xw = window->window;
+ }
+
+ XGetGeometry(window->visual->dpy, xw, &root,
+ x, y, &width, &height, &bw, &d);
+
+ /* translate x/y to screen coords */
+ if (!XTranslateCoordinates(window->visual->dpy, xw, root,
+ 0, 0, &rx, &ry, &child)) {
+ rx = ry = 0;
+ }
+ *x = rx;
+ *y = ry;
+ *w = (int) width;
+ *h = (int) height;
+ }
+}
+
+
+void
+renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
+{
+ int scrn;
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = 2048;
+ *h = 2048;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+
+ scrn = DefaultScreen(window->visual->dpy);
+ *w = DisplayWidth(window->visual->dpy, scrn);
+ *h = DisplayHeight(window->visual->dpy, scrn);
+}
+
+
+void
+renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ crDebug("Render SPU: XMoveWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, x, y);
+ XMoveWindow(window->visual->dpy, window->window, x, y);
+ XSync(window->visual->dpy, 0);
+ }
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void
+renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, const GLint *pRects )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ int evb, erb, i;
+ XRectangle *pXRects;
+
+ if (!XShapeQueryExtension(window->visual->dpy, &evb, &erb))
+ {
+ crWarning("Render SPU: Display %s doesn't support SHAPE extension", window->visual->displayName);
+ return;
+ }
+
+ if (cRects>0)
+ {
+ pXRects = (XRectangle *) crAlloc(cRects * sizeof(XRectangle));
+
+ for (i=0; i<cRects; ++i)
+ {
+ pXRects[i].x = (short) pRects[4*i];
+ pXRects[i].y = (short) pRects[4*i+1];
+ pXRects[i].width = (unsigned short) (pRects[4*i+2]-pRects[4*i]);
+ pXRects[i].height = (unsigned short) (pRects[4*i+3]-pRects[4*i+1]);
+ }
+ }
+ else
+ {
+ pXRects = (XRectangle *) crAlloc(sizeof(XRectangle));
+ pXRects[0].x = 0;
+ pXRects[0].y = 0;
+ pXRects[0].width = 0;
+ pXRects[0].height = 0;
+ cRects = 1;
+ }
+
+ crDebug("Render SPU: XShapeCombineRectangles (%x, %x, cRects=%i)", window->visual->dpy, window->window, cRects);
+
+ XShapeCombineRectangles(window->visual->dpy, window->window, ShapeBounding, 0, 0,
+ pXRects, cRects, ShapeSet, YXBanded);
+ XSync(window->visual->dpy, 0);
+ crFree(pXRects);
+ }
+}
+
+/* Either show or hide the render SPU's window. */
+void
+renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ if (window->visual->dpy && window->window &&
+ (window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ if (showIt)
+ {
+ if (window->BltInfo.width && window->BltInfo.height)
+ {
+ XMapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ else
+ {
+ XUnmapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WinCmd thread rather
+ * than a Main thread. It defaults to 1, because otherwise there were
+ * 3D driver incompatibilities on some systems. Elsewhere it causes flicker
+ * on NVidia GPUs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ WARN(("renderspuVBoxCompositorTryAcquire failed rc %d", rc));
+ return;
+ }
+ }
+
+ {
+ Status status;
+ XEvent event;
+ render_spu.self.Flush();
+// renderspuVBoxPresentBlitterEnsureCreated(window, 0);
+
+ crMemset(&event, 0, sizeof (event));
+ event.type = Expose;
+ event.xexpose.window = window->window;
+ event.xexpose.width = window->BltInfo.width;
+ event.xexpose.height = window->BltInfo.height;
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, 0, &event);
+ if (!status)
+ {
+ WARN(("XSendEvent returned null"));
+ }
+ XFlush(render_spu.pCommunicationDisplay);
+ }
+}
+
+static void
+MarkWindow(WindowInfo *w)
+{
+ static GC gc = 0; /* XXX per-window??? */
+ if (!gc) {
+ /* Create a GC for drawing invisible lines */
+ XGCValues gcValues;
+ gcValues.function = GXnoop;
+ gc = XCreateGC(w->visual->dpy, w->nativeWindow, GCFunction, &gcValues);
+ }
+ XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->BltInfo.width, w->BltInfo.height);
+}
+
+
+void
+renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
+{
+ CRASSERT(w);
+
+#if 00 /*TEMPORARY - FOR TESTING SWAP LOCK*/
+ if (1) {
+ /* random delay */
+ int k = crRandInt(1000 * 100, 750*1000);
+ static int first = 1;
+ if (first) {
+ crRandAutoSeed();
+ first = 0;
+ }
+ usleep(k);
+ }
+#endif
+
+ /* render_to_app_window:
+ * w->nativeWindow will only be non-zero if the
+ * render_spu.render_to_app_window option is true and
+ * MakeCurrent() recorded the nativeWindow handle in the WindowInfo
+ * structure.
+ */
+ if (w->nativeWindow) {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->nativeWindow );
+#if 0
+ MarkWindow(w);
+#else
+ (void) MarkWindow;
+#endif
+ }
+ else {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->window );
+ }
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *window)
+{
+ Window parent;
+
+ parent = render_spu_parent_window_id>0 ? render_spu_parent_window_id :
+ RootWindow(window->visual->dpy, window->visual->visual->screen);
+
+ XReparentWindow(window->visual->dpy, window->window, parent, window->x, window->y);
+ XSync(window->visual->dpy, False);
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ return cFunctions;
+}