glxcurrent.c   [plain text]


/*
 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice including the dates of first publication and
 * either this permission notice or a reference to
 * http://oss.sgi.com/projects/FreeB/
 * shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name of Silicon Graphics, Inc.
 * shall not be used in advertising or otherwise to promote the sale, use or
 * other dealings in this Software without prior written authorization from
 * Silicon Graphics, Inc.
 */

/**
 * \file glxcurrent.c
 * Client-side GLX interface for current context management.
 */

#include <stdlib.h>
#include <pthread.h>
#include "glxclient.h"
#include "apple_glx.h"
#include "apple_glx_context.h"

/*
** We setup some dummy structures here so that the API can be used
** even if no context is current.
*/

static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];

/*
** Dummy context used by small commands when there is no current context.
** All the
** gl and glx entry points are designed to operate as nop's when using
** the dummy context structure.
*/
static __GLXcontext dummyContext = {
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
    sizeof(dummyBuffer),
};

/*
 * Current context management and locking
 */
static pthread_once_t once_control = PTHREAD_ONCE_INIT;

_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;

/**
 * Per-thread data key.
 * 
 * Once \c init_thread_data has been called, the per-thread data key will
 * take a value of \c NULL.  As each new thread is created the default
 * value, in that thread, will be \c NULL.
 */
static pthread_key_t ContextTSD;

/**
 * Initialize the per-thread data key.
 * 
 * This function is called \b exactly once per-process (not per-thread!) to
 * initialize the per-thread data key.  This is ideally done using the
 * \c pthread_once mechanism.
 */
static void init_thread_data( void )
{
    if (pthread_key_create(&ContextTSD, NULL) != 0) {
	perror("pthread_key_create");
	exit(EXIT_FAILURE);
    }
}

_X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c ) {
    pthread_once(&once_control, init_thread_data);
    pthread_setspecific(ContextTSD, c);
}

_X_HIDDEN __GLXcontext * __glXGetCurrentContext( void )
{
    void * v;

    pthread_once(& once_control, init_thread_data);

    v = pthread_getspecific( ContextTSD );
    return (v == NULL) ? & dummyContext : (__GLXcontext *) v;
}


_X_HIDDEN void __glXSetCurrentContextNull(void) {
    __glXSetCurrentContext(&dummyContext);
}


/************************************************************************/

PUBLIC GLXContext glXGetCurrentContext(void)
{
    GLXContext cx = __glXGetCurrentContext();
    
    if (cx == &dummyContext) {
	return NULL;
    } else {
	return cx;
    }
}

PUBLIC GLXDrawable glXGetCurrentDrawable(void)
{
    GLXContext gc = __glXGetCurrentContext();
    return gc->currentDrawable;
}

static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw,
			       GLXDrawable read, GLXContext gc,
			       Bool pre13)
{
    const GLXContext oldGC = __glXGetCurrentContext();
    bool error;
    
    error = apple_glx_make_current_context(dpy, 
					   (oldGC && oldGC != &dummyContext) ?
					   oldGC->apple : NULL, 
					   gc ? gc->apple : NULL,
					   draw);

    apple_glx_diagnostic("%s: error %s\n", __func__, error ? "YES" : "NO");

    if(error)
	return GL_FALSE;
    
    __glXLock();
   
    if (gc == oldGC) {
	/* Even though the contexts are the same the drawable might have
	 * changed.  Note that gc cannot be the dummy, and that oldGC
	 * cannot be NULL, therefore if they are the same, gc is not
	 * NULL and not the dummy.
	 */
	if(gc) {
	    gc->currentDrawable = draw;
	    gc->currentReadable = read;
	}
    } else {
	
	if (oldGC != &dummyContext) {
	    /* Old current context is no longer current to anybody */
	    oldGC->currentDpy = 0;
	    oldGC->currentDrawable = None;
	    oldGC->currentReadable = None;
	    oldGC->currentContextTag = 0;
	    
	    /*
	     * At this point we should check if the context has been
	     * through glXDestroyContext, and redestroy it if so.
	     */
	    if(oldGC->do_destroy) {
		__glXUnlock();
		/* glXDestroyContext uses the same global lock. */
		glXDestroyContext(dpy, oldGC);
		__glXLock();
	    }
	}
	
	if (gc) {
	    __glXSetCurrentContext(gc);

	    gc->currentDpy = dpy;
	    gc->currentDrawable = draw;
	    gc->currentReadable = read;
	} else {
	    __glXSetCurrentContextNull();
	}
    }
    __glXUnlock();

    return GL_TRUE;
}


PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable draw, GLXContext gc)
{
    return MakeContextCurrent(dpy, draw, draw, gc, True);
}

PUBLIC GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
	  (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
	  (dpy, d, r, ctx, False), MakeContextCurrent)

PUBLIC GLX_ALIAS(Bool, glXMakeContextCurrent,
	  (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
	  (dpy, d, r, ctx, False), MakeContextCurrent)