context.c revision 49b21ff01a84dcda84ea959b3d58117a803e3222
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
/**
* \mainpage OpenGL_stub
*
* \section OpenGL_stubIntroduction Introduction
*
* Chromium consists of all the top-level files in the cr
* directory. The OpenGL_stub module basically takes care of API dispatch,
* and OpenGL state management.
*
*/
/**
* This file manages OpenGL rendering contexts in the faker library.
* The big issue is switching between Chromium and native GL context
* management. This is where we support multiple client OpenGL
* windows. Typically, one window is handled by Chromium while any
* other windows are handled by the native OpenGL library.
*/
#include "chromium.h"
#include "cr_error.h"
#include "cr_spu.h"
#include "cr_mem.h"
#include "cr_string.h"
#include "cr_environment.h"
#include "stub.h"
/**
* This function should be called from MakeCurrent(). It'll detect if
* we're in a multi-thread situation, and do the right thing for dispatch.
*/
#ifdef CHROMIUM_THREADSAFE
static void
stubCheckMultithread( void )
{
static unsigned long knownID;
if (stub.threadSafe)
return; /* nothing new, nothing to do */
if (firstCall) {
knownID = crThreadID();
}
else if (knownID != crThreadID()) {
/* going thread-safe now! */
}
}
#endif
/**
* Install the given dispatch table as the table used for all gl* calls.
*/
static void
{
#ifdef CHROMIUM_THREADSAFE
/* always set the per-thread dispatch pointer */
if (stub.threadSafe) {
/* Do nothing - the thread-safe dispatch functions will call GetTSD()
* to get a pointer to the dispatch table, and jump through it.
*/
}
else
#endif
{
/* Single thread mode - just install the caller's dispatch table */
/* This conditional is an optimization to try to avoid unnecessary
* copying. It seems to work with atlantis, multiwin, etc. but
* _could_ be a problem. (Brian)
*/
}
}
{
#if 0
#else
if (con)
{
}
else
{
}
#endif
}
{
}
{
{
#ifdef WINDOWS
{
}
if (winInfo->pVisibleRegions)
{
}
# ifdef CR_NEWWINTRACK
{
}
# endif
#endif
}
}
/**
* Create a new _Chromium_ window, not GLX, WGL or CGL.
* Called by crWindowCreate() only.
*/
{
if (spuWin < 0) {
return -1;
}
if (!winInfo) {
return -1;
}
/* Ask the head SPU for the initial window size */
/* use some reasonable defaults */
}
#ifdef VBOX_WITH_WDDM
if (stub.bRunningUnderWDDM)
{
crError("Should not be here: WindowCreate/Destroy & VBoxPackGetInjectID recuire connection id!");
}
else
#endif
{
}
if (!dpyName)
dpyName = "";
#ifdef WINDOWS
winInfo->cVisibleRegions = 0;
#endif
#ifdef CR_NEWWINTRACK
#endif
return spuWin;
}
#ifdef GLX
static XErrorHandler oldErrorHandler;
static unsigned char lastXError = Success;
static int
{
lastXError = e->error_code;
return 0;
}
#endif
{
#if defined(WINDOWS)
# ifdef VBOX_WITH_WDDM
if (stub.bRunningUnderWDDM)
# endif
return GL_TRUE;
return GL_TRUE;
if (dpy)
{
{
return GL_FALSE;
}
# if 1
return GL_TRUE;
# else
if (attr.override_redirect)
{
return GL_TRUE;
}
if (!stub.bXExtensionsChecked)
{
}
if (!stub.bHaveXComposite)
{
return GL_TRUE;
}
else
{
Pixmap p;
/*@todo this will create new pixmap for window every call*/
switch (lastXError)
{
case Success:
XFreePixmap(dpy, p);
return GL_FALSE;
break;
case BadMatch:
/*Window isn't redirected*/
break;
default:
}
return GL_TRUE;
}
# endif
}
else {
/* probably created by crWindowCreate() */
}
#endif
}
/**
* Given a Windows HDC or GLX Drawable, return the corresponding
* WindowInfo structure. Create a new one if needed.
*/
#ifdef WINDOWS
#endif
{
#ifndef WINDOWS
#else
if (!hwnd)
{
return NULL;
}
#endif
if (!winInfo) {
if (!winInfo)
return NULL;
#ifdef GLX
#endif
#ifdef VBOX_WITH_WDDM
if (stub.bRunningUnderWDDM)
else
#endif
{
}
#ifdef CR_NEWWINTRACK
#endif
#ifndef WINDOWS
#else
#endif
}
#ifdef WINDOWS
else
{
}
#endif
return winInfo;
}
static void
{
}
static void
{
#ifdef WINDOWS
#endif
}
/* Have pack SPU or tilesort SPU, etc. destroy the context */
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
if (context->spuConnection)
{
context->spuConnection = 0;
}
#endif
}
#ifdef GLX
{
}
#endif
}
#ifdef CHROMIUM_THREADSAFE
{
}
#endif
/**
* Allocate a new ContextInfo object, initialize it, put it into the
* context hash table. If type==CHROMIUM, call the head SPU's
* CreateContext() function too.
*/
unsigned long shareCtx
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
, struct VBOXUHGSMI *pHgsmi
#endif
)
{
if (shareCtx > 0) {
/* translate shareCtx to a SPU context ID */
context = (ContextInfo *)
if (context)
}
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
if (pHgsmi)
{
if (!spuConnection)
{
crWarning("VBoxConCreate failed");
return NULL;
}
}
#endif
if (spuContext < 0)
{
crWarning("VBoxCreateContext failed");
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
if (spuConnection)
#endif
return NULL;
}
}
if (!context) {
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
if (spuConnection)
#endif
return NULL;
}
if (!dpyName)
dpyName = "";
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
#endif
#ifdef CHROMIUM_THREADSAFE
#endif
#endif
#ifdef GLX
context->damageEventsBase = 0;
#endif
return context;
}
#ifdef Darwin
#define SET_ATTR(l,i,a) ( (l)[(i)++] = (a) )
int i = 0;
if( visual & CR_DEPTH_BIT )
if( visual & CR_ACCUM_BIT )
if( visual & CR_STENCIL_BIT )
if( visual & CR_ALPHA_BIT )
if( visual & CR_DOUBLE_BIT )
if( visual & CR_STEREO_BIT )
/* SET_ATTR_V(attribs, i, kCGLPFASampleBuffers, 1);
SET_ATTR_V(attribs, i, kCGLPFASamples, 0);
SET_ATTR_V(attribs, i, kCGLPFADisplayMask, 0); */
*num = i;
}
#endif
/**
*/
static GLboolean
{
#ifdef WINDOWS
long npix;
crWarning("CGLCreateContext() is trying to share a non-existant "
"CGL context. Setting share context to zero.");
shareCtx = 0;
}
else
}
crError("InstantiateNativeContext: Couldn't Create the context!");
/* Set the delayed parameters */
stub.wsInterface.CGLSetParameter( context->cglc, kCGLCPClientStorage, (long*)&(context->client_storage) );
}
GLXContext shareCtx = 0;
/* sort out context sharing here */
crWarning("glXCreateContext() is trying to share a non-existant "
"GLX context. Setting share context to zero.");
shareCtx = 0;
}
else {
}
}
#endif
}
/**
* Utility functions to get window size and titlebar text.
*/
#ifdef WINDOWS
void
unsigned int *w, unsigned int *h )
{
*w = *h = 0;
return;
}
{
return;
}
{
*w = *h = 0;
return;
}
{
*w = *h = 0;
return;
}
}
static void
{
/* XXX - we don't handle recurseUp */
else
title[0] = 0;
}
static void
{
float WidthRatio, HeightRatio;
static int DebugFlag = 0;
// apparently the "window" parameter passed to this
// function contains the native window information
{
return;
}
// get the native window's height and width
// get the spu window's height and width
stub.spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, window->spuWindow, GL_INT, 2, size);
ChromiumWidth = size[0];
// get the ratio of the size of the native window to the cr window
// output some debug information at the beginning
if(DebugFlag)
{
DebugFlag = 0;
}
if (NATIVEhwnd)
{
GetCursorPos (&point);
// make sure these coordinates are relative to the native window,
// not the whole desktop
// calculate the new position of the virtual cursor
}
else
{
pos[0] = 0;
pos[1] = 0;
}
}
void
{
float rect[4];
if( !window ||
!window->connection ||
{
*x = *y = 0;
*w = *h = 0;
} else {
*x = (int) rect[0];
*y = (int) rect[1];
*w = (int) rect[2];
*h = (int) rect[3];
}
}
static void
{
/* XXX \todo Darwin window Title */
title[0] = '\0';
}
static void
{
float window_rect[4];
/*crDebug( "%i %i", pos[0], pos[1] );*/
}
void
{
//@todo: Performing those checks is expensive operation, especially for simple apps with high FPS.
// 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
{
*x = *y = 0;
*w = *h = 0;
}
{
}
}
static char *
{
while (1) {
char *name;
return NULL;
if (name[0]) {
return name;
}
else if (recurseUp) {
/* This window has no name, try the parent */
unsigned int numChildren;
&children, &numChildren );
return NULL;
if (children)
}
else {
return NULL;
}
}
}
static void
{
if (t) {
XFree(t);
}
else {
title[0] = 0;
}
}
/**
*Return current cursor position in local window coords.
*/
static void
{
unsigned int mask;
int x, y;
if (q) {
unsigned int w, h;
stubGetWindowGeometry( window, &x, &y, &w, &h );
/* invert Y */
}
else {
}
}
#endif
/**
* This function is called by MakeCurrent() and determines whether or
* not a new rendering context should be bound to Chromium or the native
* OpenGL.
* \return GL_FALSE if native OpenGL should be used, or GL_TRUE if Chromium
* should be used.
*/
static GLboolean
{
int x, y;
unsigned int w, h;
/* If the provided window is CHROMIUM, we're clearly intended
* to create a CHROMIUM context.
*/
return GL_TRUE;
if (stub.ignoreFreeglutMenus) {
const char *glutMenuTitle = "freeglut menu";
char title[1000];
crDebug("GL faker: Ignoring freeglut menu window");
return GL_FALSE;
}
}
/* If the user's specified a window count for Chromium, see if
* this window satisfies that criterium.
*/
if (stub.matchChromiumWindowCount > 0) {
crDebug("Using native GL, app window doesn't meet match_window_count");
return GL_FALSE;
}
}
/* If the user's specified a window list to ignore, see if this
* window satisfies that criterium.
*/
if (stub.matchChromiumWindowID) {
GLuint i;
for (i = 0; i <= stub.numIgnoreWindowID; i++) {
return GL_FALSE;
}
}
}
/* If the user's specified a minimum window size for Chromium, see if
* this window satisfies that criterium.
*/
if (stub.minChromiumWindowWidth > 0 &&
stub.minChromiumWindowHeight > 0) {
stubGetWindowGeometry( window, &x, &y, &w, &h );
if (w >= stub.minChromiumWindowWidth &&
h >= stub.minChromiumWindowHeight) {
/* Check for maximum sized window now too */
if (stub.maxChromiumWindowWidth &&
if (w < stub.maxChromiumWindowWidth &&
return GL_TRUE;
else
return GL_FALSE;
}
return GL_TRUE;
}
crDebug("Using native GL, app window doesn't meet minimum_window_size");
return GL_FALSE;
}
else if (stub.matchWindowTitle) {
/* If the user's specified a window title for Chromium, see if this
* window satisfies that criterium.
*/
char title[1000];
char *titlePattern;
int len;
/* check for leading '*' wildcard */
}
else {
}
/* check for trailing '*' wildcard */
}
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;
}
/* Window title and size don't matter */
* We'll use chromium for this window (and context) if no other is.
*/
return GL_TRUE; /* use Chromium! */
}
{
{
#ifdef WINDOWS
/* Note: can't use WindowFromDC(context->pOwnWindow->drawable) here
because GL context is already released from DC and actual guest window
could be destroyed.
*/
#else
#endif
}
}
{
/*
* Get WindowInfo and ContextInfo pointers.
*/
if (currentContext)
if (context)
return GL_TRUE; /* OK */
}
#ifdef CHROMIUM_THREADSAFE
#endif
/* Here's where we really create contexts */
#ifdef CHROMIUM_THREADSAFE
#endif
if (stubCheckUseChromium(window)) {
/*
* Create a Chromium context.
*/
#else
GLint spuShareCtx = 0;
#endif
GLint spuConnection = 0;
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
{
if (!spuConnection)
{
crWarning("VBoxConCreate failed");
return GL_FALSE;
}
}
#endif
{
/*crDebug("(1)stubMakeCurrent ctx=%p(%i) window=%p(%i)", context, context->spuContext, window, window->spuWindow);*/
#ifdef CR_NEWWINTRACK
#endif
}
}
else {
/*
* Create a native OpenGL context.
*/
{
#ifdef CHROMIUM_THREADSAFE
#endif
return 0; /* false */
}
}
#ifdef CHROMIUM_THREADSAFE
#endif
}
/*
* Native OpenGL MakeCurrent().
*/
#ifdef WINDOWS
// XXX \todo We need to differentiate between these two..
retVal = ( stub.wsInterface.CGLSetSurface(context->cglc, window->connection, window->drawable, window->surface) == noErr );
retVal = (GLboolean) stub.wsInterface.glXMakeCurrent( window->dpy, window->drawable, context->glxContext );
#endif
}
else {
/*
* SPU chain MakeCurrent().
*/
/*if (context->currentDrawable && context->currentDrawable != window)
crDebug("Rebinding context %p to a different window", context);*/
crWarning("Can't rebind a chromium context to a native window\n");
retVal = 0;
}
else {
{
/*crDebug("(2)stubMakeCurrent ctx=%p(%i) window=%p(%i)", context, context->spuContext, window, window->spuWindow);*/
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
#else
0,
#endif
#ifdef CR_NEWWINTRACK
# if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
# else
0
# endif
);
#endif
{
#ifdef WINDOWS
{
}
#else
int x, y;
if (!XGetGeometry(context->currentDrawable->dpy, context->currentDrawable->drawable, &root, &x, &y, &w, &h, &border, &depth))
{
}
#endif
}
}
stub.spu->dispatch_table.MakeCurrent( window->spuWindow, (GLint) window->drawable, context->spuContext );
else
stub.spu->dispatch_table.MakeCurrent( window->spuWindow, 0, /* native window handle */ context->spuContext );
retVal = 1;
}
}
if (retVal) {
/* Now, if we've transitions from Chromium to native rendering, or
* vice versa, we have to change all the OpenGL entrypoint pointers.
*/
/* Switch to native API */
/*printf(" Switching to native API\n");*/
}
/* Switch to stub (SPU) API */
/*printf(" Switching to spu API\n");*/
}
else {
/* no API switch needed */
}
}
/* One time window setup */
int x, y;
* a width and height of zero here. In that case, skip the viewport
* call since we're probably using a tilesort SPU with fake_window_dims
* which the tilesort SPU will use for the viewport.
*/
#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
if (stubIsWindowVisible(window))
#endif
{
if (stub.trackWindowSize)
if (stub.trackWindowPos)
}
#ifdef VBOX_WITH_WDDM
#endif
}
/* Update window mapping state.
* Basically, this lets us hide render SPU windows which correspond
* to unmapped application windows. Without this, "pertly" (for example)
* opens *lots* of temporary windows which otherwise clutter the screen.
*/
}
}
return retVal;
}
void
stubDestroyContext( unsigned long contextId )
{
if (!stub.contextTable) {
return;
}
/* the lock order is windowTable->contextTable (see wglMakeCurrent_prox, glXMakeCurrent)
* this is why we need to take a windowTable lock since we will later do stub.windowTable access & locking */
#ifdef CHROMIUM_THREADSAFE
if (stubGetCurrentContext() == context) {
}
#else
if (stubGetCurrentContext() == context) {
}
#endif
}
void
{
if (!window)
return;
/* Determine if this window is being rendered natively or through
* Chromium.
*/
/*printf("*** Swapping native window %d\n", (int) drawable);*/
#ifdef WINDOWS
/* ...is this ok? */
/* stub.wsInterface.CGLFlushDrawable( context->cglc ); */
crDebug("stubSwapBuffers: unable to swap (no context!)");
#endif
}
/* Let the SPU do the buffer swap */
/*printf("*** Swapping chromium window %d\n", (int) drawable);*/
if (stub.appDrawCursor) {
int pos[2];
}
}
else {
crDebug("Calling SwapBuffers on a window we haven't seen before (no-op).");
}
}