context.c revision a804628e06a5bd14e9af77943922ffd9649c221c
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill Cunnington/* Copyright (c) 2001, Stanford University
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * All rights reserved
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * See the file LICENSE.txt for information on redistributing this software.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * \mainpage OpenGL_stub
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * \section OpenGL_stubIntroduction Introduction
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Chromium consists of all the top-level files in the cr
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * directory. The OpenGL_stub module basically takes care of API dispatch,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * and OpenGL state management.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This file manages OpenGL rendering contexts in the faker library.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The big issue is switching between Chromium and native GL context
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * management. This is where we support multiple client OpenGL
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * windows. Typically, one window is handled by Chromium while any
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * other windows are handled by the native OpenGL library.
bf2a56fd7e5b3bb37378e87e32829a01402d27f0Tom Rumsey * This function should be called from MakeCurrent(). It'll detect if
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshott * we're in a multi-thread situation, and do the right thing for dispatch.
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshott static unsigned long knownID;
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshott return; /* nothing new, nothing to do */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* going thread-safe now! */
a90aba9cbcbb8e7fe95e45590d853959efe0d354Tom Rumsey crSPUCopyDispatchTable(&glim, &stubThreadsafeDispatch);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Install the given dispatch table as the table used for all gl* calls.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* always set the per-thread dispatch pointer */
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott /* Do nothing - the thread-safe dispatch functions will call GetTSD()
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * to get a pointer to the dispatch table, and jump through it.
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey /* Single thread mode - just install the caller's dispatch table */
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey /* This conditional is an optimization to try to avoid unnecessary
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * copying. It seems to work with atlantis, multiwin, etc. but
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * _could_ be a problem. (Brian)
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey stub.spu->dispatch_table.GetIntegerv(GL_DRAW_BUFFER, &buffer);
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshottvoid stubConChromiumParameteriCR(GLint con, GLenum param, GLint value)
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott stub.spu->dispatch_table.VBoxConChromiumParameteriCR(con, param, value);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// crError("VBoxConChromiumParameteriCR called with null connection");
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshottvoid stubConChromiumParametervCR(GLint con, GLenum target, GLenum type, GLsizei count, const GLvoid *values)
a90aba9cbcbb8e7fe95e45590d853959efe0d354Tom Rumsey stub.spu->dispatch_table.VBoxConChromiumParametervCR(con, target, type, count, values);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// crError("VBoxConChromiumParameteriCR called with null connection");
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshott crError("stubConFlush called with null connection");
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshottstatic void stubWindowCleanupForContextsCB(unsigned long key, void *data1, void *data2)
c6c8bcf74a1e796c167156af1cc1a5d95c67aceaRobert Wapshott ContextInfo *context = (ContextInfo *) data1;
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell crHashtableSearch(stub.windowTable, (unsigned int) window);
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell if (winInfo && winInfo->type == CHROMIUM && stub.spu)
be367fb48c4c5a05214aab48aea9f09703b63a97Craig McDonnell stub.spu->dispatch_table.VBoxWindowDestroy(con, winInfo->spuWindow );
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (winInfo->hVisibleRegion != INVALID_HANDLE_VALUE)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster crHashtableWalk(stub.contextTable, stubWindowCleanupForContextsCB, winInfo);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crHashtableDelete(stub.windowTable, window, crFree);
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell * Create a new _Chromium_ window, not GLX, WGL or CGL.
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell * Called by crWindowCreate() only.
786bac66d599daf6355e45e64da84c846a857552Craig McDonnellstubNewWindow( const char *dpyName, GLint visBits )
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell spuWin = stub.spu->dispatch_table.WindowCreate( dpyName, visBits );
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell winInfo = (WindowInfo *) crCalloc(sizeof(WindowInfo));
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell stub.spu->dispatch_table.WindowDestroy(spuWin);
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell /* Ask the head SPU for the initial window size */
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell stub.spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, 0, GL_INT, 2, size);
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell /* use some reasonable defaults */
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crError("Should not be here: WindowCreate/Destroy & VBoxPackGetInjectID require connection id!");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster crStrncpy(winInfo->dpyName, dpyName, MAX_DPY_NAME);
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell /* Use spuWin as the hash table index and GLX/WGL handle */
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell winInfo->hVisibleRegion = INVALID_HANDLE_VALUE;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster winInfo->u32ClientID = stub.spu->dispatch_table.VBoxPackGetInjectID(0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster crHashtableAdd(stub.windowTable, (unsigned int) spuWin, winInfo);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey oldErrorHandler = XSetErrorHandler(errorHandler);
8a888dac872ea5d7dd9ce4a0739c4065d544f275Tom Rumsey /*@todo this will create new pixmap for window every call*/
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey p = XCompositeNameWindowPixmap(dpy, win->drawable);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey /*Window isn't redirected*/
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crWarning("Unexpected XError %i", (int)lastXError);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey /* probably created by crWindowCreate() */
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * Given a Windows HDC or GLX Drawable, return the corresponding
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * WindowInfo structure. Create a new one if needed.
a19a421277791c670d5a4ebcd6d7af7de159d271Tom RumseystubGetWindowInfo( Display *dpy, GLXDrawable drawable )
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey WindowInfo *winInfo = (WindowInfo *) crHashtableSearch(stub.windowTable, (unsigned int) drawable);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey winInfo = (WindowInfo *) crHashtableSearch(stub.windowTable, (unsigned int) hwnd);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey winInfo = (WindowInfo *) crCalloc(sizeof(WindowInfo));
bf2a56fd7e5b3bb37378e87e32829a01402d27f0Tom Rumsey crStrncpy(winInfo->dpyName, DisplayString(dpy), MAX_DPY_NAME);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey winInfo->connection = _CGSDefaultConnection(); // store our connection as default
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crHashtableAdd(stub.windowTable, (unsigned int) drawable, winInfo);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crHashtableAdd(stub.windowTable, (unsigned int) hwnd, winInfo);
d552ef9965b495ec6fa5f89b12ad638ad4cc87f4Tony Bamfordstatic void stubWindowCheckOwnerCB(unsigned long key, void *data1, void *data2);
d552ef9965b495ec6fa5f89b12ad638ad4cc87f4Tony Bamford crMemZero(context, sizeof(ContextInfo)); /* just to be safe */
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterstubDestroyContextLocked( ContextInfo *context )
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster stub.wsInterface.wglDeleteContext( context->hglrc );
786bac66d599daf6355e45e64da84c846a857552Craig McDonnell stub.wsInterface.CGLDestroyContext( context->cglc );
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster stub.wsInterface.glXDestroyContext( context->dpy, context->glxContext );
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* Have pack SPU or tilesort SPU, etc. destroy the context */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster stub.spu->dispatch_table.DestroyContext( context->spuContext );
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster crHashtableWalk(stub.windowTable, stubWindowCheckOwnerCB, context);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey stub.spu->dispatch_table.VBoxConDestroy(context->spuConnection);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crFreeHashtable(context->pGLXPixmapsHash, crFree);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey crHashtableDelete(stub.contextTable, contextId, NULL);
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumseystatic DECLCALLBACK(void) stubContextDtor(void*pvContext)
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * Allocate a new ContextInfo object, initialize it, put it into the
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * context hash table. If type==CHROMIUM, call the head SPU's
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey * CreateContext() function too.
a19a421277791c670d5a4ebcd6d7af7de159d271Tom RumseystubNewContext( const char *dpyName, GLint visBits, ContextType type,
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey unsigned long shareCtx
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey GLint spuContext = -1, spuShareCtx = 0, spuConnection = 0;
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey /* translate shareCtx to a SPU context ID */
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
a19a421277791c670d5a4ebcd6d7af7de159d271Tom Rumsey spuConnection = stub.spu->dispatch_table.VBoxConCreate(pHgsmi);
return NULL;
if (spuContext < 0)
if (spuConnection)
return NULL;
if (!context) {
if (spuConnection)
return NULL;
if (!dpyName)
#ifdef CHROMIUM_THREADSAFE
#ifdef GLX
return context;
#ifdef Darwin
#define SET_ATTR(l,i,a) ( (l)[(i)++] = (a) )
*num = i;
static GLboolean
#ifdef WINDOWS
long npix;
shareCtx = 0;
stub.wsInterface.CGLSetParameter( context->cglc, kCGLCPClientStorage, (long*)&(context->client_storage) );
shareCtx = 0;
#ifdef WINDOWS
title[0] = 0;
static int DebugFlag = 0;
stub.spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, window->spuWindow, GL_INT, 2, size);
if(DebugFlag)
DebugFlag = 0;
if (NATIVEhwnd)
pos[0] = 0;
if( !window ||
*x = (int) rect[0];
// Disabling those triples glxgears fps, thus using xevents instead of per frame polling is much more preferred.
//@todo: Check similar on windows guests, though doubtful as there're no XSync like calls on windows.
if (!window
|| !dpy
char *name;
return NULL;
if (name[0]) {
return name;
else if (recurseUp) {
unsigned int numChildren;
return NULL;
if (children)
return NULL;
XFree(t);
title[0] = 0;
unsigned int mask;
static GLboolean
return GL_TRUE;
return GL_FALSE;
return GL_FALSE;
GLuint i;
return GL_FALSE;
return GL_TRUE;
return GL_FALSE;
return GL_TRUE;
return GL_FALSE;
char *titlePattern;
int len;
if (title[0]) {
if (wildcard) {
return GL_TRUE;
return GL_TRUE;
crDebug("Using native GL, app window title doesn't match match_window_title string (\"%s\" != \"%s\")", title, stub.matchWindowTitle);
return GL_FALSE;
#ifdef WINDOWS
if (!spuConnection)
return GL_FALSE;
return GL_TRUE;
if (currentContext)
if (context)
#ifdef CHROMIUM_THREADSAFE
#ifdef CHROMIUM_THREADSAFE
return GL_FALSE;
/*crDebug("(1)stubMakeCurrent ctx=%p(%i) window=%p(%i)", context, context->spuContext, window, window->spuWindow);*/
window->spuWindow = stub.spu->dispatch_table.VBoxWindowCreate(spuConnection, window->dpyName, context->visBits );
#ifdef CR_NEWWINTRACK
#ifdef CHROMIUM_THREADSAFE
#ifdef CHROMIUM_THREADSAFE
#ifdef WINDOWS
retVal = ( stub.wsInterface.CGLSetSurface(context->cglc, window->connection, window->drawable, window->surface) == noErr );
retVal = (GLboolean) stub.wsInterface.glXMakeCurrent( window->dpy, window->drawable, context->glxContext );
retVal = 0;
/*crDebug("(2)stubMakeCurrent ctx=%p(%i) window=%p(%i)", context, context->spuContext, window, window->spuWindow);*/
#ifdef CR_NEWWINTRACK
#ifdef WINDOWS
if (!XGetGeometry(context->currentDrawable->dpy, context->currentDrawable->drawable, &root, &x, &y, &w, &h, &border, &depth))
stub.spu->dispatch_table.MakeCurrent( window->spuWindow, (GLint) window->drawable, context->spuContext );
stub.spu->dispatch_table.MakeCurrent( window->spuWindow, 0, /* native window handle */ context->spuContext );
if (retVal) {
#ifdef VBOX_WITH_WDDM
return retVal;
* this is why we need to take a windowTable lock since we will later do stub.windowTable access & locking */
#ifdef CHROMIUM_THREADSAFE
if (!window)
#ifdef WINDOWS