diff options
Diffstat (limited to 'xorg-server/glx')
-rw-r--r-- | xorg-server/glx/glapi.c | 1022 | ||||
-rw-r--r-- | xorg-server/glx/glapi.h | 285 | ||||
-rw-r--r-- | xorg-server/glx/glthread.h | 3 | ||||
-rw-r--r-- | xorg-server/glx/glxdri.c | 2327 |
4 files changed, 1821 insertions, 1816 deletions
diff --git a/xorg-server/glx/glapi.c b/xorg-server/glx/glapi.c index d5275dc81..9e219f680 100644 --- a/xorg-server/glx/glapi.c +++ b/xorg-server/glx/glapi.c @@ -1,512 +1,510 @@ -/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * Copyright (C) 1999-2006 Brian Paul 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 and this permission notice 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
- * BRIAN PAUL 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.
- */
-
-/*
- * This file manages the OpenGL API dispatch layer. There are functions
- * to set/get the current dispatch table for the current thread and to
- * manage registration/dispatch of dynamically added extension functions.
- *
- * This code was originally general enough to be shared with Mesa, but
- * they diverged long ago, so this is now just enough support to make
- * indirect GLX work.
- */
-
-#include <dix-config.h>
-#include <X11/Xfuncproto.h>
-#include <os.h>
-#define PUBLIC _X_EXPORT
-
-#include <stdlib.h>
-#include <string.h>
-#ifdef DEBUG
-#include <assert.h>
-#endif
-
-#include "glapi.h"
-#include "glapioffsets.h"
-#include "glapitable.h"
-
-#if defined(PTHREADS) || defined(GLX_USE_TLS)
-static void init_glapi_relocs(void);
-#endif
-
-/**
- * \name Current dispatch and current context control variables
- *
- * Depending on whether or not multithreading is support, and the type of
- * support available, several variables are used to store the current context
- * pointer and the current dispatch table pointer. In the non-threaded case,
- * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
- * purpose.
- *
- * In the "normal" threaded case, the variables \c _glapi_Dispatch and
- * \c _glapi_Context will be \c NULL if an application is detected as being
- * multithreaded. Single-threaded applications will use \c _glapi_Dispatch
- * and \c _glapi_Context just like the case without any threading support.
- * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
- * data \c _gl_DispatchTSD and \c ContextTSD are used. Drivers and the
- * static dispatch functions access these variables via \c _glapi_get_dispatch
- * and \c _glapi_get_context.
- *
- * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
- * hardcoded to \c NULL. Instead the TLS variables \c _glapi_tls_Dispatch and
- * \c _glapi_tls_Context are used. Having \c _glapi_Dispatch and
- * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
- * between TLS enabled loaders and non-TLS DRI drivers.
- */
-/*@{*/
-#if defined(GLX_USE_TLS)
-
-PUBLIC TLS struct _glapi_table * _glapi_tls_Dispatch
- __attribute__((tls_model("initial-exec"))) = NULL;
-
-PUBLIC TLS void * _glapi_tls_Context
- __attribute__((tls_model("initial-exec")));
-
-PUBLIC const struct _glapi_table *_glapi_Dispatch = NULL;
-PUBLIC const void *_glapi_Context = NULL;
-
-#else
-
-#if defined(THREADS)
-
-_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */
-static _glthread_TSD ContextTSD; /**< Per-thread context pointer */
-
-#if defined(WIN32_THREADS)
-void FreeTSD(_glthread_TSD *p);
-void FreeAllTSD(void)
-{
- FreeTSD(&_gl_DispatchTSD);
- FreeTSD(&ContextTSD);
-}
-#endif /* defined(WIN32_THREADS) */
-
-#endif /* defined(THREADS) */
-
-PUBLIC struct _glapi_table *_glapi_Dispatch = NULL;
-PUBLIC void *_glapi_Context = NULL;
-
-#endif /* defined(GLX_USE_TLS) */
-/*@}*/
-
-/*
- * xserver's gl is not multithreaded, we promise.
- */
-PUBLIC void
-_glapi_check_multithread(void)
-{
-}
-
-/**
- * Set the current context pointer for this thread.
- * The context pointer is an opaque type which should be cast to
- * void from the real context pointer type.
- */
-PUBLIC void
-_glapi_set_context(void *context)
-{
-#if defined(GLX_USE_TLS)
- _glapi_tls_Context = context;
-#elif defined(THREADS)
- _glthread_SetTSD(&ContextTSD, context);
- _glapi_Context = context;
-#else
- _glapi_Context = context;
-#endif
-}
-
-
-
-/**
- * Get the current context pointer for this thread.
- * The context pointer is an opaque type which should be cast from
- * void to the real context pointer type.
- */
-PUBLIC void *
-_glapi_get_context(void)
-{
-#if defined(GLX_USE_TLS)
- return _glapi_tls_Context;
-#else
- return _glapi_Context;
-#endif
-}
-
-
-
-/**
- * Set the global or per-thread dispatch table pointer.
- */
-PUBLIC void
-_glapi_set_dispatch(struct _glapi_table *dispatch)
-{
-#if defined(PTHREADS) || defined(GLX_USE_TLS)
- static pthread_once_t once_control = PTHREAD_ONCE_INIT;
- pthread_once( & once_control, init_glapi_relocs );
-#endif
-
-#if defined(GLX_USE_TLS)
- _glapi_tls_Dispatch = dispatch;
-#elif defined(THREADS)
- _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
- _glapi_Dispatch = dispatch;
-#else /*THREADS*/
- _glapi_Dispatch = dispatch;
-#endif /*THREADS*/
-}
-
-
-
-/**
- * Return pointer to current dispatch table for calling thread.
- */
-PUBLIC struct _glapi_table *
-_glapi_get_dispatch(void)
-{
- struct _glapi_table * api;
-#if defined(GLX_USE_TLS)
- api = _glapi_tls_Dispatch;
-#else
- api = _glapi_Dispatch;
-#endif
- return api;
-}
-
-
-
-/***
- *** The rest of this file is pretty much concerned with GetProcAddress
- *** functionality.
- ***/
-
-#if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS)
-# define DISPATCH_FUNCTION_SIZE 16
-#elif defined(USE_X86_ASM)
-# if defined(THREADS) && !defined(GLX_USE_TLS)
-# define DISPATCH_FUNCTION_SIZE 32
-# else
-# define DISPATCH_FUNCTION_SIZE 16
-# endif
-#endif
-
-
-/* The code in this file is auto-generated with Python */
-#include "glprocs.h"
-
-
-/**
- * Search the table of static entrypoint functions for the named function
- * and return the corresponding glprocs_table_t entry.
- */
-static const glprocs_table_t *
-find_entry( const char * n )
-{
- GLuint i;
- for (i = 0; static_functions[i].Name_offset >= 0; i++) {
- const char *testName = gl_string_table + static_functions[i].Name_offset;
- if (strcmp(testName, n) == 0) {
- return &static_functions[i];
- }
- }
- return NULL;
-}
-
-
-/**
- * Return dispatch table offset of the named static (built-in) function.
- * Return -1 if function not found.
- */
-static GLint
-get_static_proc_offset(const char *funcName)
-{
- const glprocs_table_t * const f = find_entry( funcName );
- if (f) {
- return f->Offset;
- }
- return -1;
-}
-
-
-
-/**********************************************************************
- * Extension function management.
- */
-
-/*
- * Number of extension functions which we can dynamically add at runtime.
- */
-#define MAX_EXTENSION_FUNCS 300
-
-
-/*
- * The dispatch table size (number of entries) is the size of the
- * _glapi_table struct plus the number of dynamic entries we can add.
- * The extra slots can be filled in by DRI drivers that register new extension
- * functions.
- */
-#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
-
-
-/**
- * Track information about a function added to the GL API.
- */
-struct _glapi_function {
- /**
- * Name of the function.
- */
- const char * name;
-
- /**
- * Text string that describes the types of the parameters passed to the
- * named function. Parameter types are converted to characters using the
- * following rules:
- * - 'i' for \c GLint, \c GLuint, and \c GLenum
- * - 'p' for any pointer type
- * - 'f' for \c GLfloat and \c GLclampf
- * - 'd' for \c GLdouble and \c GLclampd
- */
- const char * parameter_signature;
-
- /**
- * Offset in the dispatch table where the pointer to the real function is
- * located. If the driver has not requested that the named function be
- * added to the dispatch table, this will have the value ~0.
- */
- unsigned dispatch_offset;
-};
-
-static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
-static GLuint NumExtEntryPoints = 0;
-
-/**
- * Generate new entrypoint
- *
- * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
- * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
- * never happens, and the user calls this function, he'll segfault. That's
- * what you get when you try calling a GL function that doesn't really exist.
- *
- * \param funcName Name of the function to create an entry-point for.
- *
- * \sa _glapi_add_entrypoint
- */
-
-static struct _glapi_function *
-add_function_name( const char * funcName )
-{
- struct _glapi_function * entry = NULL;
-
- if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
- entry = &ExtEntryTable[NumExtEntryPoints];
-
- ExtEntryTable[NumExtEntryPoints].name = strdup(funcName);
- ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL;
- ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0;
- NumExtEntryPoints++;
- }
-
- return entry;
-}
-
-
-/**
- * Fill-in the dispatch stub for the named function.
- *
- * This function is intended to be called by a hardware driver. When called,
- * a dispatch stub may be created created for the function. A pointer to this
- * dispatch function will be returned by glXGetProcAddress.
- *
- * \param function_names Array of pointers to function names that should
- * share a common dispatch offset.
- * \param parameter_signature String representing the types of the parameters
- * passed to the named function. Parameter types
- * are converted to characters using the following
- * rules:
- * - 'i' for \c GLint, \c GLuint, and \c GLenum
- * - 'p' for any pointer type
- * - 'f' for \c GLfloat and \c GLclampf
- * - 'd' for \c GLdouble and \c GLclampd
- *
- * \returns
- * The offset in the dispatch table of the named function. A pointer to the
- * driver's implementation of the named function should be stored at
- * \c dispatch_table[\c offset].
- *
- * \sa glXGetProcAddress
- *
- * \warning
- * This function can only handle up to 8 names at a time. As far as I know,
- * the maximum number of names ever associated with an existing GL function is
- * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
- * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
- * too painful of a limitation.
- *
- * \todo
- * Determine whether or not \c parameter_signature should be allowed to be
- * \c NULL. It doesn't seem like much of a hardship for drivers to have to
- * pass in an empty string.
- *
- * \todo
- * Determine if code should be added to reject function names that start with
- * 'glX'.
- *
- * \bug
- * Add code to compare \c parameter_signature with the parameter signature of
- * a static function. In order to do that, we need to find a way to \b get
- * the parameter signature of a static function.
- */
-
-PUBLIC int
-_glapi_add_dispatch( const char * const * function_names,
- const char * parameter_signature )
-{
- static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC;
- const char * const real_sig = (parameter_signature != NULL)
- ? parameter_signature : "";
- struct _glapi_function * entry[8];
- GLboolean is_static[8];
- unsigned i;
- unsigned j;
- int offset = ~0;
- int new_offset;
-
-
- (void) memset(is_static, 0, sizeof(is_static));
- (void) memset(entry, 0, sizeof(entry));
-
- for (i = 0 ; function_names[i] != NULL ; i++) {
- /* Do some trivial validation on the name of the function. */
-
- if (function_names[i][0] != 'g' || function_names[i][1] != 'l')
- return GL_FALSE;
-
- /* Determine if the named function already exists. If the function does
- * exist, it must have the same parameter signature as the function
- * being added.
- */
-
- new_offset = get_static_proc_offset(function_names[i]);
- if (new_offset >= 0) {
- /* FIXME: Make sure the parameter signatures match! How do we get
- * FIXME: the parameter signature for static functions?
- */
-
- if ((offset != ~0) && (new_offset != offset)) {
- return -1;
- }
-
- is_static[i] = GL_TRUE;
- offset = new_offset;
- }
-
- for (j = 0; j < NumExtEntryPoints; j++) {
- if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) {
- /* The offset may be ~0 if the function name was added by
- * glXGetProcAddress but never filled in by the driver.
- */
-
- if (ExtEntryTable[j].dispatch_offset != ~0) {
- if (strcmp(real_sig, ExtEntryTable[j].parameter_signature) != 0)
- return -1;
-
- if ((offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset)) {
- return -1;
- }
-
- offset = ExtEntryTable[j].dispatch_offset;
- }
-
- entry[i] = & ExtEntryTable[j];
- break;
- }
- }
- }
-
- if (offset == ~0) {
- offset = next_dynamic_offset;
- next_dynamic_offset++;
- }
-
- for (i = 0 ; function_names[i] != NULL ; i++) {
- if (!is_static[i]) {
- if (entry[i] == NULL) {
- entry[i] = add_function_name(function_names[i]);
- if (entry[i] == NULL)
- return -1;
- }
-
- entry[i]->parameter_signature = strdup(real_sig);
- entry[i]->dispatch_offset = offset;
- }
- }
-
- return offset;
-}
-
-/*
- * glXGetProcAddress doesn't exist in the protocol, the drivers never call
- * this themselves, and neither does the server. warn if it happens though.
- */
-PUBLIC _glapi_proc
-_glapi_get_proc_address(const char *funcName)
-{
- ErrorF("_glapi_get_proc_address called!\n");
- return NULL;
-}
-
-/**
- * Return size of dispatch table struct as number of functions (or
- * slots).
- */
-PUBLIC GLuint
-_glapi_get_dispatch_table_size(void)
-{
- return DISPATCH_TABLE_SIZE;
-}
-
-#if defined(PTHREADS) || defined(GLX_USE_TLS)
-/**
- * Perform platform-specific GL API entry-point fixups.
- */
-static void
-init_glapi_relocs( void )
-{
-#if defined(USE_X86_ASM) && defined(GLX_USE_TLS) && !defined(GLX_X86_READONLY_TEXT)
- extern unsigned long _x86_get_dispatch(void);
- char run_time_patch[] = {
- 0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */
- };
- GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */
- const GLubyte * const get_disp = (const GLubyte *) run_time_patch;
- GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start;
-
- *offset = _x86_get_dispatch();
- while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) {
- (void) memcpy( curr_func, get_disp, sizeof(run_time_patch));
- curr_func += DISPATCH_FUNCTION_SIZE;
- }
-#endif
-}
-#endif /* defined(PTHREADS) || defined(GLX_USE_TLS) */
+/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2006 Brian Paul 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 and this permission notice 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 + * BRIAN PAUL 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. + */ + +/* + * This file manages the OpenGL API dispatch layer. There are functions + * to set/get the current dispatch table for the current thread and to + * manage registration/dispatch of dynamically added extension functions. + * + * This code was originally general enough to be shared with Mesa, but + * they diverged long ago, so this is now just enough support to make + * indirect GLX work. + */ + +#include <dix-config.h> +#include <X11/Xfuncproto.h> +#include <os.h> +#define PUBLIC _X_EXPORT + +#include <stdlib.h> +#include <string.h> +#ifdef DEBUG +#include <assert.h> +#endif + +#include "glapi.h" +#include "glapioffsets.h" +#include "glapitable.h" + +#if defined(PTHREADS) || defined(GLX_USE_TLS) +static void init_glapi_relocs(void); +#endif + +/** + * \name Current dispatch and current context control variables + * + * Depending on whether or not multithreading is support, and the type of + * support available, several variables are used to store the current context + * pointer and the current dispatch table pointer. In the non-threaded case, + * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this + * purpose. + * + * In the "normal" threaded case, the variables \c _glapi_Dispatch and + * \c _glapi_Context will be \c NULL if an application is detected as being + * multithreaded. Single-threaded applications will use \c _glapi_Dispatch + * and \c _glapi_Context just like the case without any threading support. + * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state + * data \c _gl_DispatchTSD and \c ContextTSD are used. Drivers and the + * static dispatch functions access these variables via \c _glapi_get_dispatch + * and \c _glapi_get_context. + * + * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are + * hardcoded to \c NULL. Instead the TLS variables \c _glapi_tls_Dispatch and + * \c _glapi_tls_Context are used. Having \c _glapi_Dispatch and + * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability + * between TLS enabled loaders and non-TLS DRI drivers. + */ +/*@{*/ +#if defined(GLX_USE_TLS) + +PUBLIC TLS struct _glapi_table * _glapi_tls_Dispatch = NULL; + +PUBLIC TLS void * _glapi_tls_Context; + +PUBLIC const struct _glapi_table *_glapi_Dispatch = NULL; +PUBLIC const void *_glapi_Context = NULL; + +#else + +#if defined(THREADS) + +_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */ +static _glthread_TSD ContextTSD; /**< Per-thread context pointer */ + +#if defined(WIN32_THREADS) +void FreeTSD(_glthread_TSD *p); +void FreeAllTSD(void) +{ + FreeTSD(&_gl_DispatchTSD); + FreeTSD(&ContextTSD); +} +#endif /* defined(WIN32_THREADS) */ + +#endif /* defined(THREADS) */ + +PUBLIC struct _glapi_table *_glapi_Dispatch = NULL; +PUBLIC void *_glapi_Context = NULL; + +#endif /* defined(GLX_USE_TLS) */ +/*@}*/ + +/* + * xserver's gl is not multithreaded, we promise. + */ +PUBLIC void +_glapi_check_multithread(void) +{ +} + +/** + * Set the current context pointer for this thread. + * The context pointer is an opaque type which should be cast to + * void from the real context pointer type. + */ +PUBLIC void +_glapi_set_context(void *context) +{ +#if defined(GLX_USE_TLS) + _glapi_tls_Context = context; +#elif defined(THREADS) + _glthread_SetTSD(&ContextTSD, context); + _glapi_Context = context; +#else + _glapi_Context = context; +#endif +} + + + +/** + * Get the current context pointer for this thread. + * The context pointer is an opaque type which should be cast from + * void to the real context pointer type. + */ +PUBLIC void * +_glapi_get_context(void) +{ +#if defined(GLX_USE_TLS) + return _glapi_tls_Context; +#else + return _glapi_Context; +#endif +} + + + +/** + * Set the global or per-thread dispatch table pointer. + */ +PUBLIC void +_glapi_set_dispatch(struct _glapi_table *dispatch) +{ +#if defined(PTHREADS) || defined(GLX_USE_TLS) + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + pthread_once( & once_control, init_glapi_relocs ); +#endif + +#if defined(GLX_USE_TLS) + _glapi_tls_Dispatch = dispatch; +#elif defined(THREADS) + _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch); + _glapi_Dispatch = dispatch; +#else /*THREADS*/ + _glapi_Dispatch = dispatch; +#endif /*THREADS*/ +} + + + +/** + * Return pointer to current dispatch table for calling thread. + */ +PUBLIC struct _glapi_table * +_glapi_get_dispatch(void) +{ + struct _glapi_table * api; +#if defined(GLX_USE_TLS) + api = _glapi_tls_Dispatch; +#else + api = _glapi_Dispatch; +#endif + return api; +} + + + +/*** + *** The rest of this file is pretty much concerned with GetProcAddress + *** functionality. + ***/ + +#if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS) +# define DISPATCH_FUNCTION_SIZE 16 +#elif defined(USE_X86_ASM) +# if defined(THREADS) && !defined(GLX_USE_TLS) +# define DISPATCH_FUNCTION_SIZE 32 +# else +# define DISPATCH_FUNCTION_SIZE 16 +# endif +#endif + + +/* The code in this file is auto-generated with Python */ +#include "glprocs.h" + + +/** + * Search the table of static entrypoint functions for the named function + * and return the corresponding glprocs_table_t entry. + */ +static const glprocs_table_t * +find_entry( const char * n ) +{ + GLuint i; + for (i = 0; static_functions[i].Name_offset >= 0; i++) { + const char *testName = gl_string_table + static_functions[i].Name_offset; + if (strcmp(testName, n) == 0) { + return &static_functions[i]; + } + } + return NULL; +} + + +/** + * Return dispatch table offset of the named static (built-in) function. + * Return -1 if function not found. + */ +static GLint +get_static_proc_offset(const char *funcName) +{ + const glprocs_table_t * const f = find_entry( funcName ); + if (f) { + return f->Offset; + } + return -1; +} + + + +/********************************************************************** + * Extension function management. + */ + +/* + * Number of extension functions which we can dynamically add at runtime. + */ +#define MAX_EXTENSION_FUNCS 300 + + +/* + * The dispatch table size (number of entries) is the size of the + * _glapi_table struct plus the number of dynamic entries we can add. + * The extra slots can be filled in by DRI drivers that register new extension + * functions. + */ +#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS) + + +/** + * Track information about a function added to the GL API. + */ +struct _glapi_function { + /** + * Name of the function. + */ + const char * name; + + /** + * Text string that describes the types of the parameters passed to the + * named function. Parameter types are converted to characters using the + * following rules: + * - 'i' for \c GLint, \c GLuint, and \c GLenum + * - 'p' for any pointer type + * - 'f' for \c GLfloat and \c GLclampf + * - 'd' for \c GLdouble and \c GLclampd + */ + const char * parameter_signature; + + /** + * Offset in the dispatch table where the pointer to the real function is + * located. If the driver has not requested that the named function be + * added to the dispatch table, this will have the value ~0. + */ + unsigned dispatch_offset; +}; + +static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS]; +static GLuint NumExtEntryPoints = 0; + +/** + * Generate new entrypoint + * + * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver + * calls \c _glapi_add_dispatch we'll put in the proper offset. If that + * never happens, and the user calls this function, he'll segfault. That's + * what you get when you try calling a GL function that doesn't really exist. + * + * \param funcName Name of the function to create an entry-point for. + * + * \sa _glapi_add_entrypoint + */ + +static struct _glapi_function * +add_function_name( const char * funcName ) +{ + struct _glapi_function * entry = NULL; + + if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) { + entry = &ExtEntryTable[NumExtEntryPoints]; + + ExtEntryTable[NumExtEntryPoints].name = strdup(funcName); + ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL; + ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0; + NumExtEntryPoints++; + } + + return entry; +} + + +/** + * Fill-in the dispatch stub for the named function. + * + * This function is intended to be called by a hardware driver. When called, + * a dispatch stub may be created created for the function. A pointer to this + * dispatch function will be returned by glXGetProcAddress. + * + * \param function_names Array of pointers to function names that should + * share a common dispatch offset. + * \param parameter_signature String representing the types of the parameters + * passed to the named function. Parameter types + * are converted to characters using the following + * rules: + * - 'i' for \c GLint, \c GLuint, and \c GLenum + * - 'p' for any pointer type + * - 'f' for \c GLfloat and \c GLclampf + * - 'd' for \c GLdouble and \c GLclampd + * + * \returns + * The offset in the dispatch table of the named function. A pointer to the + * driver's implementation of the named function should be stored at + * \c dispatch_table[\c offset]. + * + * \sa glXGetProcAddress + * + * \warning + * This function can only handle up to 8 names at a time. As far as I know, + * the maximum number of names ever associated with an existing GL function is + * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT, + * \c glPointParameterfARB, and \c glPointParameterf), so this should not be + * too painful of a limitation. + * + * \todo + * Determine whether or not \c parameter_signature should be allowed to be + * \c NULL. It doesn't seem like much of a hardship for drivers to have to + * pass in an empty string. + * + * \todo + * Determine if code should be added to reject function names that start with + * 'glX'. + * + * \bug + * Add code to compare \c parameter_signature with the parameter signature of + * a static function. In order to do that, we need to find a way to \b get + * the parameter signature of a static function. + */ + +PUBLIC int +_glapi_add_dispatch( const char * const * function_names, + const char * parameter_signature ) +{ + static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC; + const char * const real_sig = (parameter_signature != NULL) + ? parameter_signature : ""; + struct _glapi_function * entry[8]; + GLboolean is_static[8]; + unsigned i; + unsigned j; + int offset = ~0; + int new_offset; + + + (void) memset(is_static, 0, sizeof(is_static)); + (void) memset(entry, 0, sizeof(entry)); + + for (i = 0 ; function_names[i] != NULL ; i++) { + /* Do some trivial validation on the name of the function. */ + + if (function_names[i][0] != 'g' || function_names[i][1] != 'l') + return GL_FALSE; + + /* Determine if the named function already exists. If the function does + * exist, it must have the same parameter signature as the function + * being added. + */ + + new_offset = get_static_proc_offset(function_names[i]); + if (new_offset >= 0) { + /* FIXME: Make sure the parameter signatures match! How do we get + * FIXME: the parameter signature for static functions? + */ + + if ((offset != ~0) && (new_offset != offset)) { + return -1; + } + + is_static[i] = GL_TRUE; + offset = new_offset; + } + + for (j = 0; j < NumExtEntryPoints; j++) { + if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) { + /* The offset may be ~0 if the function name was added by + * glXGetProcAddress but never filled in by the driver. + */ + + if (ExtEntryTable[j].dispatch_offset != ~0) { + if (strcmp(real_sig, ExtEntryTable[j].parameter_signature) != 0) + return -1; + + if ((offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset)) { + return -1; + } + + offset = ExtEntryTable[j].dispatch_offset; + } + + entry[i] = & ExtEntryTable[j]; + break; + } + } + } + + if (offset == ~0) { + offset = next_dynamic_offset; + next_dynamic_offset++; + } + + for (i = 0 ; function_names[i] != NULL ; i++) { + if (!is_static[i]) { + if (entry[i] == NULL) { + entry[i] = add_function_name(function_names[i]); + if (entry[i] == NULL) + return -1; + } + + entry[i]->parameter_signature = strdup(real_sig); + entry[i]->dispatch_offset = offset; + } + } + + return offset; +} + +/* + * glXGetProcAddress doesn't exist in the protocol, the drivers never call + * this themselves, and neither does the server. warn if it happens though. + */ +PUBLIC _glapi_proc +_glapi_get_proc_address(const char *funcName) +{ + ErrorF("_glapi_get_proc_address called!\n"); + return NULL; +} + +/** + * Return size of dispatch table struct as number of functions (or + * slots). + */ +PUBLIC GLuint +_glapi_get_dispatch_table_size(void) +{ + return DISPATCH_TABLE_SIZE; +} + +#if defined(PTHREADS) || defined(GLX_USE_TLS) +/** + * Perform platform-specific GL API entry-point fixups. + */ +static void +init_glapi_relocs( void ) +{ +#if defined(USE_X86_ASM) && defined(GLX_USE_TLS) && !defined(GLX_X86_READONLY_TEXT) + extern unsigned long _x86_get_dispatch(void); + char run_time_patch[] = { + 0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */ + }; + GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */ + const GLubyte * const get_disp = (const GLubyte *) run_time_patch; + GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start; + + *offset = _x86_get_dispatch(); + while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) { + (void) memcpy( curr_func, get_disp, sizeof(run_time_patch)); + curr_func += DISPATCH_FUNCTION_SIZE; + } +#endif +} +#endif /* defined(PTHREADS) || defined(GLX_USE_TLS) */ diff --git a/xorg-server/glx/glapi.h b/xorg-server/glx/glapi.h index 3a33ccae0..7051c1e3c 100644 --- a/xorg-server/glx/glapi.h +++ b/xorg-server/glx/glapi.h @@ -1,143 +1,142 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 Brian Paul 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 and this permission notice 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
- * BRIAN PAUL 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.
- */
-
-
-/**
- * \mainpage Mesa GL API Module
- *
- * \section GLAPIIntroduction Introduction
- *
- * The Mesa GL API module is responsible for dispatching all the
- * gl*() functions. All GL functions are dispatched by jumping through
- * the current dispatch table (basically a struct full of function
- * pointers.)
- *
- * A per-thread current dispatch table and per-thread current context
- * pointer are managed by this module too.
- *
- * This module is intended to be non-Mesa-specific so it can be used
- * with the X/DRI libGL also.
- */
-
-
-#ifndef _GLAPI_H
-#define _GLAPI_H
-
-#define GL_GLEXT_PROTOTYPES
-
-#include "GL/gl.h"
-#include "GL/glext.h"
-#include "glthread.h"
-
-
-struct _glapi_table;
-
-typedef void (*_glapi_proc)(void); /* generic function pointer */
-
-typedef void (*_glapi_warning_func)(void *ctx, const char *str, ...);
-
-
-#if defined(USE_MGL_NAMESPACE)
-#define _glapi_set_dispatch _mglapi_set_dispatch
-#define _glapi_get_dispatch _mglapi_get_dispatch
-#define _glapi_set_context _mglapi_set_context
-#define _glapi_get_context _mglapi_get_context
-#define _glapi_Context _mglapi_Context
-#define _glapi_Dispatch _mglapi_Dispatch
-#endif
-
-
-/*
- * Number of extension functions which we can dynamically add at runtime.
- */
-#define MAX_EXTENSION_FUNCS 300
-
-
-/**
- ** Define the GET_CURRENT_CONTEXT() macro.
- ** \param C local variable which will hold the current context.
- **/
-#if defined (GLX_USE_TLS)
-
-const extern void *_glapi_Context;
-const extern struct _glapi_table *_glapi_Dispatch;
-
-extern TLS void * _glapi_tls_Context
- __attribute__((tls_model("initial-exec")));
-
-# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_tls_Context
-
-#else
-
-extern void *_glapi_Context;
-extern struct _glapi_table *_glapi_Dispatch;
-
-# ifdef THREADS
-# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) (_glapi_Context ? _glapi_Context : _glapi_get_context())
-# else
-# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_Context
-# endif
-
-#endif /* defined (GLX_USE_TLS) */
-
-
-/**
- ** GL API public functions
- **/
-
-extern void
-_glapi_check_multithread(void);
-
-extern void
-_glapi_set_context(void *context);
-
-extern void *
-_glapi_get_context(void);
-
-extern void
-_glapi_set_dispatch(struct _glapi_table *dispatch);
-
-extern struct _glapi_table *
-_glapi_get_dispatch(void);
-
-extern int
-_glapi_begin_dispatch_override(struct _glapi_table *override);
-
-extern void
-_glapi_end_dispatch_override(int layer);
-
-struct _glapi_table *
-_glapi_get_override_dispatch(int layer);
-
-extern GLuint
-_glapi_get_dispatch_table_size(void);
-
-extern int
-_glapi_add_dispatch( const char * const * function_names,
- const char * parameter_signature );
-
-extern _glapi_proc
-_glapi_get_proc_address(const char *funcName);
-
-#endif
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul 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 and this permission notice 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 + * BRIAN PAUL 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. + */ + + +/** + * \mainpage Mesa GL API Module + * + * \section GLAPIIntroduction Introduction + * + * The Mesa GL API module is responsible for dispatching all the + * gl*() functions. All GL functions are dispatched by jumping through + * the current dispatch table (basically a struct full of function + * pointers.) + * + * A per-thread current dispatch table and per-thread current context + * pointer are managed by this module too. + * + * This module is intended to be non-Mesa-specific so it can be used + * with the X/DRI libGL also. + */ + + +#ifndef _GLAPI_H +#define _GLAPI_H + +#define GL_GLEXT_PROTOTYPES + +#include "GL/gl.h" +#include "GL/glext.h" +#include "glthread.h" + + +struct _glapi_table; + +typedef void (*_glapi_proc)(void); /* generic function pointer */ + +typedef void (*_glapi_warning_func)(void *ctx, const char *str, ...); + + +#if defined(USE_MGL_NAMESPACE) +#define _glapi_set_dispatch _mglapi_set_dispatch +#define _glapi_get_dispatch _mglapi_get_dispatch +#define _glapi_set_context _mglapi_set_context +#define _glapi_get_context _mglapi_get_context +#define _glapi_Context _mglapi_Context +#define _glapi_Dispatch _mglapi_Dispatch +#endif + + +/* + * Number of extension functions which we can dynamically add at runtime. + */ +#define MAX_EXTENSION_FUNCS 300 + + +/** + ** Define the GET_CURRENT_CONTEXT() macro. + ** \param C local variable which will hold the current context. + **/ +#if defined (GLX_USE_TLS) + +const extern void *_glapi_Context; +const extern struct _glapi_table *_glapi_Dispatch; + +extern TLS void * _glapi_tls_Context; + +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_tls_Context + +#else + +extern void *_glapi_Context; +extern struct _glapi_table *_glapi_Dispatch; + +# ifdef THREADS +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) (_glapi_Context ? _glapi_Context : _glapi_get_context()) +# else +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_Context +# endif + +#endif /* defined (GLX_USE_TLS) */ + + +/** + ** GL API public functions + **/ + +extern void +_glapi_check_multithread(void); + +extern void +_glapi_set_context(void *context); + +extern void * +_glapi_get_context(void); + +extern void +_glapi_set_dispatch(struct _glapi_table *dispatch); + +extern struct _glapi_table * +_glapi_get_dispatch(void); + +extern int +_glapi_begin_dispatch_override(struct _glapi_table *override); + +extern void +_glapi_end_dispatch_override(int layer); + +struct _glapi_table * +_glapi_get_override_dispatch(int layer); + +extern GLuint +_glapi_get_dispatch_table_size(void); + +extern int +_glapi_add_dispatch( const char * const * function_names, + const char * parameter_signature ); + +extern _glapi_proc +_glapi_get_proc_address(const char *funcName); + +#endif diff --git a/xorg-server/glx/glthread.h b/xorg-server/glx/glthread.h index 140e2aa8e..532401a73 100644 --- a/xorg-server/glx/glthread.h +++ b/xorg-server/glx/glthread.h @@ -233,8 +233,7 @@ _glthread_SetTSD(_glthread_TSD *, void *); #if defined(GLX_USE_TLS) -extern TLS struct _glapi_table * _glapi_tls_Dispatch - __attribute__((tls_model("initial-exec"))); +extern TLS struct _glapi_table * _glapi_tls_Dispatch; #define GET_DISPATCH() _glapi_tls_Dispatch diff --git a/xorg-server/glx/glxdri.c b/xorg-server/glx/glxdri.c index 399683da7..244eac6c2 100644 --- a/xorg-server/glx/glxdri.c +++ b/xorg-server/glx/glxdri.c @@ -1,1159 +1,1168 @@ -/*
- * Copyright © 2006 Red Hat, Inc
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of Red Hat,
- * Inc not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. Red Hat, Inc makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <dlfcn.h>
-
-#include <drm.h>
-#include <GL/gl.h>
-#include <GL/internal/dri_interface.h>
-#include <GL/glxtokens.h>
-
-#include <windowstr.h>
-#include <os.h>
-#include <damage.h>
-
-#define _XF86DRI_SERVER_
-#include <drm_sarea.h>
-#include <xf86drm.h>
-#include <X11/dri/xf86driproto.h>
-#include <xf86str.h>
-#include <xf86.h>
-#include <dri.h>
-
-#include "servermd.h"
-
-#define DRI_NEW_INTERFACE_ONLY
-#include "glxserver.h"
-#include "glxutil.h"
-#include "glxdricommon.h"
-
-#include "glapitable.h"
-#include "glapi.h"
-#include "glthread.h"
-#include "dispatch.h"
-#include "extension_string.h"
-
-typedef struct __GLXDRIscreen __GLXDRIscreen;
-typedef struct __GLXDRIcontext __GLXDRIcontext;
-typedef struct __GLXDRIdrawable __GLXDRIdrawable;
-
-struct __GLXDRIscreen {
- __GLXscreen base;
- __DRIscreen *driScreen;
- void *driver;
-
- xf86EnterVTProc *enterVT;
- xf86LeaveVTProc *leaveVT;
-
- const __DRIcoreExtension *core;
- const __DRIlegacyExtension *legacy;
- const __DRIcopySubBufferExtension *copySubBuffer;
- const __DRIswapControlExtension *swapControl;
-
-#ifdef __DRI_TEX_OFFSET
- const __DRItexOffsetExtension *texOffset;
- DRITexOffsetStartProcPtr texOffsetStart;
- DRITexOffsetFinishProcPtr texOffsetFinish;
- __GLXDRIdrawable *texOffsetOverride[16];
- GLuint lastTexOffsetOverride;
-#endif
-
- unsigned char glx_enable_bits[__GLX_EXT_BYTES];
-};
-
-struct __GLXDRIcontext {
- __GLXcontext base;
- __DRIcontext *driContext;
- XID hwContextID;
-};
-
-struct __GLXDRIdrawable {
- __GLXdrawable base;
- __DRIdrawable *driDrawable;
-
- /* Pulled in from old __GLXpixmap */
-#ifdef __DRI_TEX_OFFSET
- GLint texname;
- __GLXDRIcontext *ctx;
- unsigned long long offset;
- DamagePtr pDamage;
-#endif
-};
-
-static void
-__glXDRIleaveServer(GLboolean rendering)
-{
- int i;
-
- for (i = 0; rendering && i < screenInfo.numScreens; i++) {
- __GLXDRIscreen * const screen =
- (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
- GLuint lastOverride = screen->lastTexOffsetOverride;
-
- if (lastOverride) {
- __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
- int j;
-
- for (j = 0; j < lastOverride; j++) {
- __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
-
- if (pGlxPix && pGlxPix->texname) {
- pGlxPix->offset =
- screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw);
- }
- }
- }
- }
-
- DRIBlockHandler(NULL, NULL, NULL);
-
- for (i = 0; rendering && i < screenInfo.numScreens; i++) {
- __GLXDRIscreen * const screen =
- (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
- GLuint lastOverride = screen->lastTexOffsetOverride;
-
- if (lastOverride) {
- __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
- int j;
-
- for (j = 0; j < lastOverride; j++) {
- __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
-
- if (pGlxPix && pGlxPix->texname) {
- screen->texOffset->setTexOffset(pGlxPix->ctx->driContext,
- pGlxPix->texname,
- pGlxPix->offset,
- pGlxPix->base.pDraw->depth,
- ((PixmapPtr)pGlxPix->base.pDraw)->devKind);
- }
- }
- }
- }
-}
-
-static void
-__glXDRIenterServer(GLboolean rendering)
-{
- int i;
-
- for (i = 0; rendering && i < screenInfo.numScreens; i++) {
- __GLXDRIscreen * const screen = (__GLXDRIscreen *)
- glxGetScreen(screenInfo.screens[i]);
-
- if (screen->lastTexOffsetOverride) {
- CALL_Flush(GET_DISPATCH(), ());
- break;
- }
- }
-
- DRIWakeupHandler(NULL, 0, NULL);
-}
-
-
-static void
-__glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable)
-{
- GLuint lastOverride = screen->lastTexOffsetOverride;
-
- if (lastOverride) {
- __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
- int i;
-
- for (i = 0; i < lastOverride; i++) {
- if (texOffsetOverride[i] == drawable) {
- if (screen->texOffsetFinish)
- screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw);
-
- texOffsetOverride[i] = NULL;
-
- if (i + 1 == lastOverride) {
- lastOverride = 0;
-
- while (i--) {
- if (texOffsetOverride[i]) {
- lastOverride = i + 1;
- break;
- }
- }
-
- screen->lastTexOffsetOverride = lastOverride;
-
- break;
- }
- }
- }
- }
-}
-
-
-static void
-__glXDRIdrawableDestroy(__GLXdrawable *drawable)
-{
- __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
- __GLXDRIscreen *screen;
- int i;
-
- for (i = 0; i < screenInfo.numScreens; i++) {
- screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
- __glXDRIdoReleaseTexImage(screen, private);
- }
-
- /* If the X window was destroyed, the dri DestroyWindow hook will
- * aready have taken care of this, so only call if pDraw isn't NULL. */
- if (drawable->pDraw != NULL) {
- screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen);
- (*screen->core->destroyDrawable)(private->driDrawable);
-
- __glXenterServer(GL_FALSE);
- DRIDestroyDrawable(drawable->pDraw->pScreen,
- serverClient, drawable->pDraw);
- __glXleaveServer(GL_FALSE);
- }
-
- __glXDrawableRelease(drawable);
-
- free(private);
-}
-
-static GLboolean
-__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate)
-{
- __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
- __GLXDRIscreen *screen =
- (__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen);
-
- (*screen->core->swapBuffers)(private->driDrawable);
-
- return TRUE;
-}
-
-
-static int
-__glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval)
-{
- __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable;
- __GLXDRIscreen *screen =
- (__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen);
-
- if (screen->swapControl)
- screen->swapControl->setSwapInterval(draw->driDrawable, interval);
-
- return 0;
-}
-
-
-static void
-__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
- int x, int y, int w, int h)
-{
- __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
- __GLXDRIscreen *screen = (__GLXDRIscreen *)
- glxGetScreen(basePrivate->pDraw->pScreen);
-
- if (screen->copySubBuffer)
- screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h);
-}
-
-static void
-__glXDRIcontextDestroy(__GLXcontext *baseContext)
-{
- __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
- __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
- Bool retval;
-
- screen->core->destroyContext(context->driContext);
-
- __glXenterServer(GL_FALSE);
- retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen,
- context->hwContextID);
- __glXleaveServer(GL_FALSE);
-
- __glXContextDestroy(&context->base);
- free(context);
-}
-
-static int
-__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
-{
- __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
- __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
- __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
- __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
-
- return (*screen->core->bindContext)(context->driContext,
- draw->driDrawable,
- read->driDrawable);
-}
-
-static int
-__glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
-{
- __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
- __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
-
- return (*screen->core->unbindContext)(context->driContext);
-}
-
-static int
-__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
- unsigned long mask)
-{
- __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
- __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
- __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
-
- return (*screen->core->copyContext)(dst->driContext,
- src->driContext, mask);
-}
-
-static void
-glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height)
-{
- int i;
- CARD32 *p, *end;
-
- rowstride /= 4;
-
- for (i = 0; i < height; i++)
- {
- p = pixels;
- end = p + width;
- while (p < end)
- *p++ |= 0xFF000000;
- pixels += rowstride;
- }
-}
-
-static Bool
-testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap)
-{
- Bool ret;
-
- if (!screen->texOffsetStart || !screen->texOffset)
- return FALSE;
-
- __glXenterServer(GL_FALSE);
- ret = screen->texOffsetStart(pPixmap) != ~0ULL;
- __glXleaveServer(GL_FALSE);
-
- return ret;
-}
-
-/*
- * (sticking this here for lack of a better place)
- * Known issues with the GLX_EXT_texture_from_pixmap implementation:
- * - In general we ignore the fbconfig, lots of examples follow
- * - No fbconfig handling for multiple mipmap levels
- * - No fbconfig handling for 1D textures
- * - No fbconfig handling for TEXTURE_TARGET
- * - No fbconfig exposure of Y inversion state
- * - No GenerateMipmapEXT support (due to no FBO support)
- * - No support for anything but 16bpp and 32bpp-sparse pixmaps
- */
-
-static int
-__glXDRIbindTexImage(__GLXcontext *baseContext,
- int buffer,
- __GLXdrawable *glxPixmap)
-{
- RegionPtr pRegion = NULL;
- PixmapPtr pixmap;
- int bpp, override = 0, texname;
- GLenum format, type;
- ScreenPtr pScreen = glxPixmap->pDraw->pScreen;
- __GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap;
- __GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen);
-
- CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ?
- GL_TEXTURE_BINDING_2D :
- GL_TEXTURE_BINDING_RECTANGLE_NV,
- &texname));
-
- if (!texname)
- return __glXError(GLXBadContextState);
-
- pixmap = (PixmapPtr) glxPixmap->pDraw;
-
- if (testTexOffset(screen, pixmap)) {
- __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
- int i, firstEmpty = 16;
-
- for (i = 0; i < 16; i++) {
- if (texOffsetOverride[i] == driDraw)
- goto alreadyin;
-
- if (firstEmpty == 16 && !texOffsetOverride[i])
- firstEmpty = i;
- }
-
- if (firstEmpty == 16) {
- ErrorF("%s: Failed to register texture offset override\n", __func__);
- goto nooverride;
- }
-
- if (firstEmpty >= screen->lastTexOffsetOverride)
- screen->lastTexOffsetOverride = firstEmpty + 1;
-
- texOffsetOverride[firstEmpty] = driDraw;
-
-alreadyin:
- override = 1;
-
- driDraw->ctx = (__GLXDRIcontext*)baseContext;
-
- if (texname == driDraw->texname)
- return Success;
-
- driDraw->texname = texname;
-
- screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0,
- pixmap->drawable.depth,
- pixmap->devKind);
- }
-nooverride:
-
- if (!driDraw->pDamage) {
- if (!override) {
- driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone,
- TRUE, pScreen, NULL);
- if (!driDraw->pDamage)
- return BadAlloc;
-
- DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage);
- }
-
- pRegion = NULL;
- } else {
- pRegion = DamageRegion(driDraw->pDamage);
- if (RegionNil(pRegion))
- return Success;
- }
-
- /* XXX 24bpp packed, 8, etc */
- if (pixmap->drawable.depth >= 24) {
- bpp = 4;
- format = GL_BGRA;
- type =
-#if X_BYTE_ORDER == X_BIG_ENDIAN
- !override ? GL_UNSIGNED_INT_8_8_8_8_REV :
-#endif
- GL_UNSIGNED_BYTE;
- } else {
- bpp = 2;
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- }
-
- if (pRegion == NULL)
- {
- void *data = NULL;
-
- if (!override) {
- unsigned pitch = PixmapBytePad(pixmap->drawable.width,
- pixmap->drawable.depth);
-
- data = malloc(pitch * pixmap->drawable.height);
-
- __glXenterServer(GL_FALSE);
- pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/,
- 0 /*pixmap->drawable.y*/, pixmap->drawable.width,
- pixmap->drawable.height, ZPixmap, ~0, data);
- __glXleaveServer(GL_FALSE);
-
- if (pixmap->drawable.depth == 24)
- glxFillAlphaChannel(data,
- pitch,
- pixmap->drawable.width,
- pixmap->drawable.height);
-
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
- pitch / bpp) );
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
- }
-
- CALL_TexImage2D( GET_DISPATCH(),
- (glxPixmap->target,
- 0,
- bpp == 4 ? 4 : 3,
- pixmap->drawable.width,
- pixmap->drawable.height,
- 0,
- format,
- type,
- data) );
-
- free(data);
- } else if (!override) {
- int i, numRects;
- BoxPtr p;
-
- numRects = RegionNumRects (pRegion);
- p = RegionRects (pRegion);
-
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
-
- for (i = 0; i < numRects; i++)
- {
- unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1,
- pixmap->drawable.depth);
- void *data = malloc(pitch * (p[i].y2 - p[i].y1));
-
- __glXenterServer(GL_FALSE);
- pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1,
- /*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1,
- p[i].y2 - p[i].y1, ZPixmap, ~0, data);
- __glXleaveServer(GL_FALSE);
-
- if (pixmap->drawable.depth == 24)
- glxFillAlphaChannel(data,
- pitch,
- p[i].x2 - p[i].x1,
- p[i].y2 - p[i].y1);
-
- CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
- pitch / bpp) );
-
- CALL_TexSubImage2D( GET_DISPATCH(),
- (glxPixmap->target,
- 0,
- p[i].x1, p[i].y1,
- p[i].x2 - p[i].x1, p[i].y2 - p[i].y1,
- format,
- type,
- data) );
-
- free(data);
- }
- }
-
- if (!override)
- DamageEmpty(driDraw->pDamage);
-
- return Success;
-}
-
-static int
-__glXDRIreleaseTexImage(__GLXcontext *baseContext,
- int buffer,
- __GLXdrawable *pixmap)
-{
- __GLXDRIscreen *screen =
- (__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen);
- __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap;
-
- __glXDRIdoReleaseTexImage(screen, drawable);
-
- return Success;
-}
-
-static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
- __glXDRIbindTexImage,
- __glXDRIreleaseTexImage
-};
-
-static void
-__glXDRIscreenDestroy(__GLXscreen *baseScreen)
-{
- __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
-
- screen->core->destroyScreen(screen->driScreen);
-
- dlclose(screen->driver);
-
- __glXScreenDestroy(baseScreen);
-
- free(screen);
-}
-
-static __GLXcontext *
-__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
- __GLXconfig *glxConfig,
- __GLXcontext *baseShareContext)
-{
- __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
- __GLXDRIcontext *context, *shareContext;
- __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
- VisualPtr visual;
- int i;
- GLboolean retval;
- __DRIcontext *driShare;
- drm_context_t hwContext;
- ScreenPtr pScreen = baseScreen->pScreen;
-
- shareContext = (__GLXDRIcontext *) baseShareContext;
- if (shareContext)
- driShare = shareContext->driContext;
- else
- driShare = NULL;
-
- if (baseShareContext && baseShareContext->isDirect)
- return NULL;
-
- context = calloc(1, sizeof *context);
- if (context == NULL)
- return NULL;
-
- context->base.destroy = __glXDRIcontextDestroy;
- context->base.makeCurrent = __glXDRIcontextMakeCurrent;
- context->base.loseCurrent = __glXDRIcontextLoseCurrent;
- context->base.copy = __glXDRIcontextCopy;
-
- context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
- /* Find the requested X visual */
- visual = pScreen->visuals;
- for (i = 0; i < pScreen->numVisuals; i++, visual++)
- if (visual->vid == glxConfig->visualID)
- break;
- if (i == pScreen->numVisuals)
- return NULL;
-
- context->hwContextID = FakeClientID(0);
-
- __glXenterServer(GL_FALSE);
- retval = DRICreateContext(baseScreen->pScreen, visual,
- context->hwContextID, &hwContext);
- __glXleaveServer(GL_FALSE);
-
- if (!retval)
- return NULL;
-
- context->driContext =
- screen->legacy->createNewContext(screen->driScreen,
- config->driConfig,
- 0, /* render type */
- driShare,
- hwContext,
- context);
-
- if (context->driContext == NULL) {
- __glXenterServer(GL_FALSE);
- retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID);
- __glXleaveServer(GL_FALSE);
- free(context);
- return NULL;
- }
-
- return &context->base;
-}
-
-static __GLXdrawable *
-__glXDRIscreenCreateDrawable(ClientPtr client,
- __GLXscreen *screen,
- DrawablePtr pDraw,
- XID drawId,
- int type,
- XID glxDrawId,
- __GLXconfig *glxConfig)
-{
- __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
- __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
- __GLXDRIdrawable *private;
- GLboolean retval;
- drm_drawable_t hwDrawable;
-
- private = calloc(1, sizeof *private);
- if (private == NULL)
- return NULL;
-
- if (!__glXDrawableInit(&private->base, screen,
- pDraw, type, glxDrawId, glxConfig)) {
- free(private);
- return NULL;
- }
-
- private->base.destroy = __glXDRIdrawableDestroy;
- private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
- private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
- private->base.waitX = NULL;
- private->base.waitGL = NULL;
-
- __glXenterServer(GL_FALSE);
- retval = DRICreateDrawable(screen->pScreen, serverClient,
- pDraw, &hwDrawable);
- __glXleaveServer(GL_FALSE);
-
- if (!retval) {
- free(private);
- return NULL;
- }
-
- /* The last argument is 'attrs', which is used with pbuffers which
- * we currently don't support. */
-
- private->driDrawable =
- (driScreen->legacy->createNewDrawable)(driScreen->driScreen,
- config->driConfig,
- hwDrawable, 0, NULL, private);
-
- if (private->driDrawable == NULL) {
- __glXenterServer(GL_FALSE);
- DRIDestroyDrawable(screen->pScreen, serverClient, pDraw);
- __glXleaveServer(GL_FALSE);
- free(private);
- return NULL;
- }
-
- return &private->base;
-}
-
-static GLboolean
-getDrawableInfo(__DRIdrawable *driDrawable,
- unsigned int *index, unsigned int *stamp,
- int *x, int *y, int *width, int *height,
- int *numClipRects, drm_clip_rect_t **ppClipRects,
- int *backX, int *backY,
- int *numBackClipRects, drm_clip_rect_t **ppBackClipRects,
- void *data)
-{
- __GLXDRIdrawable *drawable = data;
- ScreenPtr pScreen;
- drm_clip_rect_t *pClipRects, *pBackClipRects;
- GLboolean retval;
- size_t size;
-
- /* If the X window has been destroyed, give up here. */
- if (drawable->base.pDraw == NULL)
- return GL_FALSE;
-
- pScreen = drawable->base.pDraw->pScreen;
- __glXenterServer(GL_FALSE);
- retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp,
- x, y, width, height,
- numClipRects, &pClipRects,
- backX, backY,
- numBackClipRects, &pBackClipRects);
- __glXleaveServer(GL_FALSE);
-
- if (retval && *numClipRects > 0) {
- size = sizeof (drm_clip_rect_t) * *numClipRects;
- *ppClipRects = malloc(size);
-
- /* Clip cliprects to screen dimensions (redirected windows) */
- if (*ppClipRects != NULL) {
- int i, j;
-
- for (i = 0, j = 0; i < *numClipRects; i++) {
- (*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0);
- (*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0);
- (*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width);
- (*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height);
-
- if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 &&
- (*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) {
- j++;
- }
- }
-
- if (*numClipRects != j) {
- *numClipRects = j;
- *ppClipRects = realloc(*ppClipRects,
- sizeof (drm_clip_rect_t) *
- *numClipRects);
- }
- } else
- *numClipRects = 0;
- }
- else {
- *ppClipRects = NULL;
- *numClipRects = 0;
- }
-
- if (retval && *numBackClipRects > 0) {
- size = sizeof (drm_clip_rect_t) * *numBackClipRects;
- *ppBackClipRects = malloc(size);
- if (*ppBackClipRects != NULL)
- memcpy (*ppBackClipRects, pBackClipRects, size);
- else
- *numBackClipRects = 0;
- }
- else {
- *ppBackClipRects = NULL;
- *numBackClipRects = 0;
- }
-
- return retval;
-}
-
-static void __glXReportDamage(__DRIdrawable *driDraw,
- int x, int y,
- drm_clip_rect_t *rects, int num_rects,
- GLboolean front_buffer,
- void *data)
-{
- __GLXDRIdrawable *drawable = data;
- DrawablePtr pDraw = drawable->base.pDraw;
- RegionRec region;
-
- __glXenterServer(GL_FALSE);
-
- RegionInit(®ion, (BoxPtr) rects, num_rects);
- RegionTranslate(®ion, pDraw->x, pDraw->y);
- DamageDamageRegion(pDraw, ®ion);
- RegionUninit(®ion);
-
- __glXleaveServer(GL_FALSE);
-}
-
-static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
- { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
- getDrawableInfo
-};
-
-static const __DRIdamageExtension damageExtension = {
- { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
- __glXReportDamage,
-};
-
-static const __DRIextension *loader_extensions[] = {
- &systemTimeExtension.base,
- &getDrawableInfoExtension.base,
- &damageExtension.base,
- NULL
-};
-
-
-
-static Bool
-glxDRIEnterVT (int index, int flags)
-{
- ScrnInfoPtr scrn = xf86Screens[index];
- Bool ret;
- __GLXDRIscreen *screen = (__GLXDRIscreen *)
- glxGetScreen(screenInfo.screens[index]);
-
- LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
-
- scrn->EnterVT = screen->enterVT;
-
- ret = scrn->EnterVT (index, flags);
-
- screen->enterVT = scrn->EnterVT;
- scrn->EnterVT = glxDRIEnterVT;
-
- if (!ret)
- return FALSE;
-
- glxResumeClients();
-
- return TRUE;
-}
-
-static void
-glxDRILeaveVT (int index, int flags)
-{
- ScrnInfoPtr scrn = xf86Screens[index];
- __GLXDRIscreen *screen = (__GLXDRIscreen *)
- glxGetScreen(screenInfo.screens[index]);
-
- LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
-
- glxSuspendClients();
-
- scrn->LeaveVT = screen->leaveVT;
- (*screen->leaveVT) (index, flags);
- screen->leaveVT = scrn->LeaveVT;
- scrn->LeaveVT = glxDRILeaveVT;
-}
-
-static void
-initializeExtensions(__GLXDRIscreen *screen)
-{
- const __DRIextension **extensions;
- int i;
-
- extensions = screen->core->getExtensions(screen->driScreen);
-
- for (i = 0; extensions[i]; i++) {
-#ifdef __DRI_READ_DRAWABLE
- if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
- __glXEnableExtension(screen->glx_enable_bits,
- "GLX_SGI_make_current_read");
-
- LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n");
- }
-#endif
-
-#ifdef __DRI_COPY_SUB_BUFFER
- if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
- screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
- __glXEnableExtension(screen->glx_enable_bits,
- "GLX_MESA_copy_sub_buffer");
-
- LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
- }
-#endif
-
-#ifdef __DRI_SWAP_CONTROL
- if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
- screen->swapControl = (__DRIswapControlExtension *) extensions[i];
- __glXEnableExtension(screen->glx_enable_bits,
- "GLX_SGI_swap_control");
- __glXEnableExtension(screen->glx_enable_bits,
- "GLX_MESA_swap_control");
-
- LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
- }
-#endif
-
-#ifdef __DRI_TEX_OFFSET
- if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) {
- screen->texOffset = (__DRItexOffsetExtension *) extensions[i];
- LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n");
- }
-#endif
- /* Ignore unknown extensions */
- }
-}
-
-static __GLXscreen *
-__glXDRIscreenProbe(ScreenPtr pScreen)
-{
- drm_handle_t hSAREA;
- drmAddress pSAREA = NULL;
- char *BusID;
- __DRIversion ddx_version;
- __DRIversion dri_version;
- __DRIversion drm_version;
- __DRIframebuffer framebuffer;
- int fd = -1;
- int status;
- drm_magic_t magic;
- drmVersionPtr version;
- int newlyopened;
- char *driverName;
- drm_handle_t hFB;
- int junk;
- __GLXDRIscreen *screen;
- Bool isCapable;
- size_t buffer_size;
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- const __DRIconfig **driConfigs;
-
- if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") ||
- !DRIQueryDirectRenderingCapable(pScreen, &isCapable) ||
- !isCapable) {
- LogMessage(X_INFO,
- "AIGLX: Screen %d is not DRI capable\n", pScreen->myNum);
- return NULL;
- }
-
- screen = calloc(1, sizeof *screen);
- if (screen == NULL)
- return NULL;
-
- screen->base.destroy = __glXDRIscreenDestroy;
- screen->base.createContext = __glXDRIscreenCreateContext;
- screen->base.createDrawable = __glXDRIscreenCreateDrawable;
- screen->base.swapInterval = __glXDRIdrawableSwapInterval;
- screen->base.pScreen = pScreen;
-
- __glXInitExtensionEnableBits(screen->glx_enable_bits);
-
- /* DRI protocol version. */
- dri_version.major = XF86DRI_MAJOR_VERSION;
- dri_version.minor = XF86DRI_MINOR_VERSION;
- dri_version.patch = XF86DRI_PATCH_VERSION;
-
- if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) {
- LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n");
- goto handle_error;
- }
-
- fd = drmOpenOnce(NULL, BusID, &newlyopened);
-
- if (fd < 0) {
- LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n",
- strerror(-fd));
- goto handle_error;
- }
-
- if (drmGetMagic(fd, &magic)) {
- LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n");
- goto handle_error;
- }
-
- version = drmGetVersion(fd);
- if (version) {
- drm_version.major = version->version_major;
- drm_version.minor = version->version_minor;
- drm_version.patch = version->version_patchlevel;
- drmFreeVersion(version);
- }
- else {
- drm_version.major = -1;
- drm_version.minor = -1;
- drm_version.patch = -1;
- }
-
- if (newlyopened && !DRIAuthConnection(pScreen, magic)) {
- LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n");
- goto handle_error;
- }
-
- /* Get device name (like "tdfx") and the ddx version numbers.
- * We'll check the version in each DRI driver's "createNewScreen"
- * function. */
- if (!DRIGetClientDriverName(pScreen,
- &ddx_version.major,
- &ddx_version.minor,
- &ddx_version.patch,
- &driverName)) {
- LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n");
- goto handle_error;
- }
-
- screen->driver = glxProbeDriver(driverName,
- (void **)&screen->core,
- __DRI_CORE, __DRI_CORE_VERSION,
- (void **)&screen->legacy,
- __DRI_LEGACY, __DRI_LEGACY_VERSION);
- if (screen->driver == NULL) {
- goto handle_error;
- }
-
- /*
- * Get device-specific info. pDevPriv will point to a struct
- * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
- * has information about the screen size, depth, pitch, ancilliary
- * buffers, DRM mmap handles, etc.
- */
- if (!DRIGetDeviceInfo(pScreen, &hFB, &junk,
- &framebuffer.size, &framebuffer.stride,
- &framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
- LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed\n");
- goto handle_error;
- }
-
- framebuffer.width = pScreen->width;
- framebuffer.height = pScreen->height;
-
- /* Map the framebuffer region. */
- status = drmMap(fd, hFB, framebuffer.size,
- (drmAddressPtr)&framebuffer.base);
- if (status != 0) {
- LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)\n",
- strerror(-status));
- goto handle_error;
- }
-
- /* Map the SAREA region. Further mmap regions may be setup in
- * each DRI driver's "createNewScreen" function.
- */
- status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
- if (status != 0) {
- LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)\n",
- strerror(-status));
- goto handle_error;
- }
-
- screen->driScreen =
- (*screen->legacy->createNewScreen)(pScreen->myNum,
- &ddx_version,
- &dri_version,
- &drm_version,
- &framebuffer,
- pSAREA,
- fd,
- loader_extensions,
- &driConfigs,
- screen);
-
- if (screen->driScreen == NULL) {
- LogMessage(X_ERROR,
- "AIGLX error: Calling driver entry point failed\n");
- goto handle_error;
- }
-
- screen->base.fbconfigs = glxConvertConfigs(screen->core,
- driConfigs, GLX_WINDOW_BIT);
-
- initializeExtensions(screen);
-
- DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart,
- &screen->texOffsetFinish);
-
- __glXScreenInit(&screen->base, pScreen);
-
- /* The first call simply determines the length of the extension string.
- * This allows us to allocate some memory to hold the extension string,
- * but it requires that we call __glXGetExtensionString a second time.
- */
- buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL);
- if (buffer_size > 0) {
- free(screen->base.GLXextensions);
-
- screen->base.GLXextensions = xnfalloc(buffer_size);
- (void) __glXGetExtensionString(screen->glx_enable_bits,
- screen->base.GLXextensions);
- }
-
- __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", driverName);
-
- return &screen->base;
-
- handle_error:
- if (pSAREA != NULL)
- drmUnmap(pSAREA, SAREA_MAX);
-
- if (framebuffer.base != NULL)
- drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
-
- if (fd >= 0)
- drmCloseOnce(fd);
-
- DRICloseConnection(pScreen);
-
- if (screen->driver)
- dlclose(screen->driver);
-
- free(screen);
-
- LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
-
- return NULL;
-}
-
-_X_EXPORT __GLXprovider __glXDRIProvider = {
- __glXDRIscreenProbe,
- "DRI",
- NULL
-};
+/* + * Copyright © 2006 Red Hat, Inc + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Red Hat, + * Inc not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/time.h> +#include <dlfcn.h> + +#include <drm.h> +#include <GL/gl.h> +#include <GL/internal/dri_interface.h> +#include <GL/glxtokens.h> + +#include <windowstr.h> +#include <os.h> +#include <damage.h> + +#define _XF86DRI_SERVER_ +#include <drm_sarea.h> +#include <xf86drm.h> +#include <X11/dri/xf86driproto.h> +#include <xf86str.h> +#include <xf86.h> +#include <dri.h> + +#include "servermd.h" + +#define DRI_NEW_INTERFACE_ONLY +#include "glxserver.h" +#include "glxutil.h" +#include "glxdricommon.h" + +#include "glapitable.h" +#include "glapi.h" +#include "glthread.h" +#include "dispatch.h" +#include "extension_string.h" + +typedef struct __GLXDRIscreen __GLXDRIscreen; +typedef struct __GLXDRIcontext __GLXDRIcontext; +typedef struct __GLXDRIdrawable __GLXDRIdrawable; + +struct __GLXDRIscreen { + __GLXscreen base; + __DRIscreen *driScreen; + void *driver; + + xf86EnterVTProc *enterVT; + xf86LeaveVTProc *leaveVT; + + const __DRIcoreExtension *core; + const __DRIlegacyExtension *legacy; + const __DRIcopySubBufferExtension *copySubBuffer; + const __DRIswapControlExtension *swapControl; + +#ifdef __DRI_TEX_OFFSET + const __DRItexOffsetExtension *texOffset; + DRITexOffsetStartProcPtr texOffsetStart; + DRITexOffsetFinishProcPtr texOffsetFinish; + __GLXDRIdrawable *texOffsetOverride[16]; + GLuint lastTexOffsetOverride; +#endif + + unsigned char glx_enable_bits[__GLX_EXT_BYTES]; +}; + +struct __GLXDRIcontext { + __GLXcontext base; + __DRIcontext *driContext; + XID hwContextID; +}; + +struct __GLXDRIdrawable { + __GLXdrawable base; + __DRIdrawable *driDrawable; + + /* Pulled in from old __GLXpixmap */ +#ifdef __DRI_TEX_OFFSET + GLint texname; + __GLXDRIcontext *ctx; + unsigned long long offset; + DamagePtr pDamage; +#endif +}; + +static void +__glXDRIleaveServer(GLboolean rendering) +{ + int i; + + for (i = 0; rendering && i < screenInfo.numScreens; i++) { + __GLXDRIscreen * const screen = + (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); + GLuint lastOverride = screen->lastTexOffsetOverride; + + if (lastOverride) { + __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; + int j; + + for (j = 0; j < lastOverride; j++) { + __GLXDRIdrawable *pGlxPix = texOffsetOverride[j]; + + if (pGlxPix && pGlxPix->texname) { + pGlxPix->offset = + screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw); + } + } + } + } + + DRIBlockHandler(NULL, NULL, NULL); + + for (i = 0; rendering && i < screenInfo.numScreens; i++) { + __GLXDRIscreen * const screen = + (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); + GLuint lastOverride = screen->lastTexOffsetOverride; + + if (lastOverride) { + __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; + int j; + + for (j = 0; j < lastOverride; j++) { + __GLXDRIdrawable *pGlxPix = texOffsetOverride[j]; + + if (pGlxPix && pGlxPix->texname) { + screen->texOffset->setTexOffset(pGlxPix->ctx->driContext, + pGlxPix->texname, + pGlxPix->offset, + pGlxPix->base.pDraw->depth, + ((PixmapPtr)pGlxPix->base.pDraw)->devKind); + } + } + } + } +} + +static void +__glXDRIenterServer(GLboolean rendering) +{ + int i; + + for (i = 0; rendering && i < screenInfo.numScreens; i++) { + __GLXDRIscreen * const screen = (__GLXDRIscreen *) + glxGetScreen(screenInfo.screens[i]); + + if (screen->lastTexOffsetOverride) { + CALL_Flush(GET_DISPATCH(), ()); + break; + } + } + + DRIWakeupHandler(NULL, 0, NULL); +} + + +static void +__glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable) +{ + GLuint lastOverride = screen->lastTexOffsetOverride; + + if (lastOverride) { + __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; + int i; + + for (i = 0; i < lastOverride; i++) { + if (texOffsetOverride[i] == drawable) { + if (screen->texOffsetFinish) + screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw); + + texOffsetOverride[i] = NULL; + + if (i + 1 == lastOverride) { + lastOverride = 0; + + while (i--) { + if (texOffsetOverride[i]) { + lastOverride = i + 1; + break; + } + } + + screen->lastTexOffsetOverride = lastOverride; + + break; + } + } + } + } +} + + +static void +__glXDRIdrawableDestroy(__GLXdrawable *drawable) +{ + __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; + __GLXDRIscreen *screen; + int i; + + for (i = 0; i < screenInfo.numScreens; i++) { + screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]); + __glXDRIdoReleaseTexImage(screen, private); + } + + /* If the X window was destroyed, the dri DestroyWindow hook will + * aready have taken care of this, so only call if pDraw isn't NULL. */ + if (drawable->pDraw != NULL) { + screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen); + (*screen->core->destroyDrawable)(private->driDrawable); + + __glXenterServer(GL_FALSE); + DRIDestroyDrawable(drawable->pDraw->pScreen, + serverClient, drawable->pDraw); + __glXleaveServer(GL_FALSE); + } + + __glXDrawableRelease(drawable); + + free(private); +} + +static GLboolean +__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate) +{ + __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; + __GLXDRIscreen *screen = + (__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen); + + (*screen->core->swapBuffers)(private->driDrawable); + + return TRUE; +} + + +static int +__glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval) +{ + __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable; + __GLXDRIscreen *screen = + (__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen); + + if (screen->swapControl) + screen->swapControl->setSwapInterval(draw->driDrawable, interval); + + return 0; +} + + +static void +__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate, + int x, int y, int w, int h) +{ + __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; + __GLXDRIscreen *screen = (__GLXDRIscreen *) + glxGetScreen(basePrivate->pDraw->pScreen); + + if (screen->copySubBuffer) + screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h); +} + +static void +__glXDRIcontextDestroy(__GLXcontext *baseContext) +{ + __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; + __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; + Bool retval; + + screen->core->destroyContext(context->driContext); + + __glXenterServer(GL_FALSE); + retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen, + context->hwContextID); + __glXleaveServer(GL_FALSE); + + __glXContextDestroy(&context->base); + free(context); +} + +static int +__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) +{ + __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; + __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; + __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; + __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; + + return (*screen->core->bindContext)(context->driContext, + draw->driDrawable, + read->driDrawable); +} + +static int +__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) +{ + __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; + __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; + + return (*screen->core->unbindContext)(context->driContext); +} + +static int +__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, + unsigned long mask) +{ + __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; + __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; + __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; + + return (*screen->core->copyContext)(dst->driContext, + src->driContext, mask); +} + +static void +glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height) +{ + int i; + CARD32 *p, *end; + + rowstride /= 4; + + for (i = 0; i < height; i++) + { + p = pixels; + end = p + width; + while (p < end) + *p++ |= 0xFF000000; + pixels += rowstride; + } +} + +static Bool +testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap) +{ + Bool ret; + + if (!screen->texOffsetStart || !screen->texOffset) + return FALSE; + + __glXenterServer(GL_FALSE); + ret = screen->texOffsetStart(pPixmap) != ~0ULL; + __glXleaveServer(GL_FALSE); + + return ret; +} + +/* + * (sticking this here for lack of a better place) + * Known issues with the GLX_EXT_texture_from_pixmap implementation: + * - In general we ignore the fbconfig, lots of examples follow + * - No fbconfig handling for multiple mipmap levels + * - No fbconfig handling for 1D textures + * - No fbconfig handling for TEXTURE_TARGET + * - No fbconfig exposure of Y inversion state + * - No GenerateMipmapEXT support (due to no FBO support) + * - No support for anything but 16bpp and 32bpp-sparse pixmaps + */ + +static int +__glXDRIbindTexImage(__GLXcontext *baseContext, + int buffer, + __GLXdrawable *glxPixmap) +{ + RegionPtr pRegion = NULL; + PixmapPtr pixmap; + int bpp, override = 0, texname; + GLenum format, type; + ScreenPtr pScreen = glxPixmap->pDraw->pScreen; + __GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap; + __GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen); + + CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ? + GL_TEXTURE_BINDING_2D : + GL_TEXTURE_BINDING_RECTANGLE_NV, + &texname)); + + if (!texname) + return __glXError(GLXBadContextState); + + pixmap = (PixmapPtr) glxPixmap->pDraw; + + if (testTexOffset(screen, pixmap)) { + __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride; + int i, firstEmpty = 16; + + for (i = 0; i < 16; i++) { + if (texOffsetOverride[i] == driDraw) + goto alreadyin; + + if (firstEmpty == 16 && !texOffsetOverride[i]) + firstEmpty = i; + } + + if (firstEmpty == 16) { + ErrorF("%s: Failed to register texture offset override\n", __func__); + goto nooverride; + } + + if (firstEmpty >= screen->lastTexOffsetOverride) + screen->lastTexOffsetOverride = firstEmpty + 1; + + texOffsetOverride[firstEmpty] = driDraw; + +alreadyin: + override = 1; + + driDraw->ctx = (__GLXDRIcontext*)baseContext; + + if (texname == driDraw->texname) + return Success; + + driDraw->texname = texname; + + screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0, + pixmap->drawable.depth, + pixmap->devKind); + } +nooverride: + + if (!driDraw->pDamage) { + if (!override) { + driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone, + TRUE, pScreen, NULL); + if (!driDraw->pDamage) + return BadAlloc; + + DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage); + } + + pRegion = NULL; + } else { + pRegion = DamageRegion(driDraw->pDamage); + if (RegionNil(pRegion)) + return Success; + } + + /* XXX 24bpp packed, 8, etc */ + if (pixmap->drawable.depth >= 24) { + bpp = 4; + format = GL_BGRA; + type = +#if X_BYTE_ORDER == X_BIG_ENDIAN + !override ? GL_UNSIGNED_INT_8_8_8_8_REV : +#endif + GL_UNSIGNED_BYTE; + } else { + bpp = 2; + format = GL_RGB; + type = GL_UNSIGNED_SHORT_5_6_5; + } + + if (pRegion == NULL) + { + void *data = NULL; + + if (!override) { + unsigned pitch = PixmapBytePad(pixmap->drawable.width, + pixmap->drawable.depth); + + data = malloc(pitch * pixmap->drawable.height); + + __glXenterServer(GL_FALSE); + pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/, + 0 /*pixmap->drawable.y*/, pixmap->drawable.width, + pixmap->drawable.height, ZPixmap, ~0, data); + __glXleaveServer(GL_FALSE); + + if (pixmap->drawable.depth == 24) + glxFillAlphaChannel(data, + pitch, + pixmap->drawable.width, + pixmap->drawable.height); + + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH, + pitch / bpp) ); + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) ); + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) ); + } + + CALL_TexImage2D( GET_DISPATCH(), + (glxPixmap->target, + 0, + bpp == 4 ? 4 : 3, + pixmap->drawable.width, + pixmap->drawable.height, + 0, + format, + type, + data) ); + + free(data); + } else if (!override) { + int i, numRects; + BoxPtr p; + + numRects = RegionNumRects (pRegion); + p = RegionRects (pRegion); + + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) ); + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) ); + + for (i = 0; i < numRects; i++) + { + unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1, + pixmap->drawable.depth); + void *data = malloc(pitch * (p[i].y2 - p[i].y1)); + + __glXenterServer(GL_FALSE); + pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1, + /*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1, + p[i].y2 - p[i].y1, ZPixmap, ~0, data); + __glXleaveServer(GL_FALSE); + + if (pixmap->drawable.depth == 24) + glxFillAlphaChannel(data, + pitch, + p[i].x2 - p[i].x1, + p[i].y2 - p[i].y1); + + CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH, + pitch / bpp) ); + + CALL_TexSubImage2D( GET_DISPATCH(), + (glxPixmap->target, + 0, + p[i].x1, p[i].y1, + p[i].x2 - p[i].x1, p[i].y2 - p[i].y1, + format, + type, + data) ); + + free(data); + } + } + + if (!override) + DamageEmpty(driDraw->pDamage); + + return Success; +} + +static int +__glXDRIreleaseTexImage(__GLXcontext *baseContext, + int buffer, + __GLXdrawable *pixmap) +{ + __GLXDRIscreen *screen = + (__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen); + __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap; + + __glXDRIdoReleaseTexImage(screen, drawable); + + return Success; +} + +static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { + __glXDRIbindTexImage, + __glXDRIreleaseTexImage +}; + +static void +__glXDRIscreenDestroy(__GLXscreen *baseScreen) +{ + __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; + + screen->core->destroyScreen(screen->driScreen); + + dlclose(screen->driver); + + __glXScreenDestroy(baseScreen); + + free(screen); +} + +static __GLXcontext * +__glXDRIscreenCreateContext(__GLXscreen *baseScreen, + __GLXconfig *glxConfig, + __GLXcontext *baseShareContext) +{ + __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; + __GLXDRIcontext *context, *shareContext; + __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; + VisualPtr visual; + int i; + GLboolean retval; + __DRIcontext *driShare; + drm_context_t hwContext; + ScreenPtr pScreen = baseScreen->pScreen; + + shareContext = (__GLXDRIcontext *) baseShareContext; + if (shareContext) + driShare = shareContext->driContext; + else + driShare = NULL; + + if (baseShareContext && baseShareContext->isDirect) + return NULL; + + context = calloc(1, sizeof *context); + if (context == NULL) + return NULL; + + context->base.destroy = __glXDRIcontextDestroy; + context->base.makeCurrent = __glXDRIcontextMakeCurrent; + context->base.loseCurrent = __glXDRIcontextLoseCurrent; + context->base.copy = __glXDRIcontextCopy; + + context->base.textureFromPixmap = &__glXDRItextureFromPixmap; + /* Find the requested X visual */ + visual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, visual++) + if (visual->vid == glxConfig->visualID) + break; + if (i == pScreen->numVisuals) + return NULL; + + context->hwContextID = FakeClientID(0); + + __glXenterServer(GL_FALSE); + retval = DRICreateContext(baseScreen->pScreen, visual, + context->hwContextID, &hwContext); + __glXleaveServer(GL_FALSE); + + if (!retval) + return NULL; + + context->driContext = + screen->legacy->createNewContext(screen->driScreen, + config->driConfig, + 0, /* render type */ + driShare, + hwContext, + context); + + if (context->driContext == NULL) { + __glXenterServer(GL_FALSE); + retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID); + __glXleaveServer(GL_FALSE); + free(context); + return NULL; + } + + return &context->base; +} + +static __GLXdrawable * +__glXDRIscreenCreateDrawable(ClientPtr client, + __GLXscreen *screen, + DrawablePtr pDraw, + XID drawId, + int type, + XID glxDrawId, + __GLXconfig *glxConfig) +{ + __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; + __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; + __GLXDRIdrawable *private; + GLboolean retval; + drm_drawable_t hwDrawable; + + private = calloc(1, sizeof *private); + if (private == NULL) + return NULL; + + if (!__glXDrawableInit(&private->base, screen, + pDraw, type, glxDrawId, glxConfig)) { + free(private); + return NULL; + } + + private->base.destroy = __glXDRIdrawableDestroy; + private->base.swapBuffers = __glXDRIdrawableSwapBuffers; + private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; + private->base.waitX = NULL; + private->base.waitGL = NULL; + + __glXenterServer(GL_FALSE); + retval = DRICreateDrawable(screen->pScreen, serverClient, + pDraw, &hwDrawable); + __glXleaveServer(GL_FALSE); + + if (!retval) { + free(private); + return NULL; + } + + /* The last argument is 'attrs', which is used with pbuffers which + * we currently don't support. */ + + private->driDrawable = + (driScreen->legacy->createNewDrawable)(driScreen->driScreen, + config->driConfig, + hwDrawable, 0, NULL, private); + + if (private->driDrawable == NULL) { + __glXenterServer(GL_FALSE); + DRIDestroyDrawable(screen->pScreen, serverClient, pDraw); + __glXleaveServer(GL_FALSE); + free(private); + return NULL; + } + + return &private->base; +} + +static GLboolean +getDrawableInfo(__DRIdrawable *driDrawable, + unsigned int *index, unsigned int *stamp, + int *x, int *y, int *width, int *height, + int *numClipRects, drm_clip_rect_t **ppClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t **ppBackClipRects, + void *data) +{ + __GLXDRIdrawable *drawable = data; + ScreenPtr pScreen; + drm_clip_rect_t *pClipRects, *pBackClipRects; + GLboolean retval; + size_t size; + + /* If the X window has been destroyed, give up here. */ + if (drawable->base.pDraw == NULL) + return GL_FALSE; + + pScreen = drawable->base.pDraw->pScreen; + __glXenterServer(GL_FALSE); + retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp, + x, y, width, height, + numClipRects, &pClipRects, + backX, backY, + numBackClipRects, &pBackClipRects); + __glXleaveServer(GL_FALSE); + + if (retval && *numClipRects > 0) { + size = sizeof (drm_clip_rect_t) * *numClipRects; + *ppClipRects = malloc(size); + + /* Clip cliprects to screen dimensions (redirected windows) */ + if (*ppClipRects != NULL) { + int i, j; + + for (i = 0, j = 0; i < *numClipRects; i++) { + (*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0); + (*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0); + (*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width); + (*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height); + + if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 && + (*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) { + j++; + } + } + + if (*numClipRects != j) { + *numClipRects = j; + *ppClipRects = realloc(*ppClipRects, + sizeof (drm_clip_rect_t) * + *numClipRects); + } + } else + *numClipRects = 0; + } + else { + *ppClipRects = NULL; + *numClipRects = 0; + } + + if (retval && *numBackClipRects > 0) { + size = sizeof (drm_clip_rect_t) * *numBackClipRects; + *ppBackClipRects = malloc(size); + if (*ppBackClipRects != NULL) + memcpy (*ppBackClipRects, pBackClipRects, size); + else + *numBackClipRects = 0; + } + else { + *ppBackClipRects = NULL; + *numBackClipRects = 0; + } + + return retval; +} + +static void __glXReportDamage(__DRIdrawable *driDraw, + int x, int y, + drm_clip_rect_t *rects, int num_rects, + GLboolean front_buffer, + void *data) +{ + __GLXDRIdrawable *drawable = data; + DrawablePtr pDraw = drawable->base.pDraw; + RegionRec region; + + __glXenterServer(GL_FALSE); + + if (RegionInitBoxes(®ion, (BoxPtr) rects, num_rects)) { + RegionTranslate(®ion, pDraw->x, pDraw->y); + DamageDamageRegion(pDraw, ®ion); + RegionUninit(®ion); + } + else { + while (num_rects--) { + RegionInit (®ion, (BoxPtr) rects++, 1); + RegionTranslate(®ion, pDraw->x, pDraw->y); + DamageDamageRegion(pDraw, ®ion); + RegionUninit(®ion); + } + } + + __glXleaveServer(GL_FALSE); +} + +static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = { + { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION }, + getDrawableInfo +}; + +static const __DRIdamageExtension damageExtension = { + { __DRI_DAMAGE, __DRI_DAMAGE_VERSION }, + __glXReportDamage, +}; + +static const __DRIextension *loader_extensions[] = { + &systemTimeExtension.base, + &getDrawableInfoExtension.base, + &damageExtension.base, + NULL +}; + + + +static Bool +glxDRIEnterVT (int index, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[index]; + Bool ret; + __GLXDRIscreen *screen = (__GLXDRIscreen *) + glxGetScreen(screenInfo.screens[index]); + + LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); + + scrn->EnterVT = screen->enterVT; + + ret = scrn->EnterVT (index, flags); + + screen->enterVT = scrn->EnterVT; + scrn->EnterVT = glxDRIEnterVT; + + if (!ret) + return FALSE; + + glxResumeClients(); + + return TRUE; +} + +static void +glxDRILeaveVT (int index, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[index]; + __GLXDRIscreen *screen = (__GLXDRIscreen *) + glxGetScreen(screenInfo.screens[index]); + + LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n"); + + glxSuspendClients(); + + scrn->LeaveVT = screen->leaveVT; + (*screen->leaveVT) (index, flags); + screen->leaveVT = scrn->LeaveVT; + scrn->LeaveVT = glxDRILeaveVT; +} + +static void +initializeExtensions(__GLXDRIscreen *screen) +{ + const __DRIextension **extensions; + int i; + + extensions = screen->core->getExtensions(screen->driScreen); + + for (i = 0; extensions[i]; i++) { +#ifdef __DRI_READ_DRAWABLE + if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { + __glXEnableExtension(screen->glx_enable_bits, + "GLX_SGI_make_current_read"); + + LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); + } +#endif + +#ifdef __DRI_COPY_SUB_BUFFER + if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { + screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i]; + __glXEnableExtension(screen->glx_enable_bits, + "GLX_MESA_copy_sub_buffer"); + + LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); + } +#endif + +#ifdef __DRI_SWAP_CONTROL + if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { + screen->swapControl = (__DRIswapControlExtension *) extensions[i]; + __glXEnableExtension(screen->glx_enable_bits, + "GLX_SGI_swap_control"); + __glXEnableExtension(screen->glx_enable_bits, + "GLX_MESA_swap_control"); + + LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); + } +#endif + +#ifdef __DRI_TEX_OFFSET + if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) { + screen->texOffset = (__DRItexOffsetExtension *) extensions[i]; + LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n"); + } +#endif + /* Ignore unknown extensions */ + } +} + +static __GLXscreen * +__glXDRIscreenProbe(ScreenPtr pScreen) +{ + drm_handle_t hSAREA; + drmAddress pSAREA = NULL; + char *BusID; + __DRIversion ddx_version; + __DRIversion dri_version; + __DRIversion drm_version; + __DRIframebuffer framebuffer; + int fd = -1; + int status; + drm_magic_t magic; + drmVersionPtr version; + int newlyopened; + char *driverName; + drm_handle_t hFB; + int junk; + __GLXDRIscreen *screen; + Bool isCapable; + size_t buffer_size; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + const __DRIconfig **driConfigs; + + if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") || + !DRIQueryDirectRenderingCapable(pScreen, &isCapable) || + !isCapable) { + LogMessage(X_INFO, + "AIGLX: Screen %d is not DRI capable\n", pScreen->myNum); + return NULL; + } + + screen = calloc(1, sizeof *screen); + if (screen == NULL) + return NULL; + + screen->base.destroy = __glXDRIscreenDestroy; + screen->base.createContext = __glXDRIscreenCreateContext; + screen->base.createDrawable = __glXDRIscreenCreateDrawable; + screen->base.swapInterval = __glXDRIdrawableSwapInterval; + screen->base.pScreen = pScreen; + + __glXInitExtensionEnableBits(screen->glx_enable_bits); + + /* DRI protocol version. */ + dri_version.major = XF86DRI_MAJOR_VERSION; + dri_version.minor = XF86DRI_MINOR_VERSION; + dri_version.patch = XF86DRI_PATCH_VERSION; + + if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) { + LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n"); + goto handle_error; + } + + fd = drmOpenOnce(NULL, BusID, &newlyopened); + + if (fd < 0) { + LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n", + strerror(-fd)); + goto handle_error; + } + + if (drmGetMagic(fd, &magic)) { + LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n"); + goto handle_error; + } + + version = drmGetVersion(fd); + if (version) { + drm_version.major = version->version_major; + drm_version.minor = version->version_minor; + drm_version.patch = version->version_patchlevel; + drmFreeVersion(version); + } + else { + drm_version.major = -1; + drm_version.minor = -1; + drm_version.patch = -1; + } + + if (newlyopened && !DRIAuthConnection(pScreen, magic)) { + LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n"); + goto handle_error; + } + + /* Get device name (like "tdfx") and the ddx version numbers. + * We'll check the version in each DRI driver's "createNewScreen" + * function. */ + if (!DRIGetClientDriverName(pScreen, + &ddx_version.major, + &ddx_version.minor, + &ddx_version.patch, + &driverName)) { + LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n"); + goto handle_error; + } + + screen->driver = glxProbeDriver(driverName, + (void **)&screen->core, + __DRI_CORE, __DRI_CORE_VERSION, + (void **)&screen->legacy, + __DRI_LEGACY, __DRI_LEGACY_VERSION); + if (screen->driver == NULL) { + goto handle_error; + } + + /* + * Get device-specific info. pDevPriv will point to a struct + * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that + * has information about the screen size, depth, pitch, ancilliary + * buffers, DRM mmap handles, etc. + */ + if (!DRIGetDeviceInfo(pScreen, &hFB, &junk, + &framebuffer.size, &framebuffer.stride, + &framebuffer.dev_priv_size, &framebuffer.dev_priv)) { + LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed\n"); + goto handle_error; + } + + framebuffer.width = pScreen->width; + framebuffer.height = pScreen->height; + + /* Map the framebuffer region. */ + status = drmMap(fd, hFB, framebuffer.size, + (drmAddressPtr)&framebuffer.base); + if (status != 0) { + LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)\n", + strerror(-status)); + goto handle_error; + } + + /* Map the SAREA region. Further mmap regions may be setup in + * each DRI driver's "createNewScreen" function. + */ + status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA); + if (status != 0) { + LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)\n", + strerror(-status)); + goto handle_error; + } + + screen->driScreen = + (*screen->legacy->createNewScreen)(pScreen->myNum, + &ddx_version, + &dri_version, + &drm_version, + &framebuffer, + pSAREA, + fd, + loader_extensions, + &driConfigs, + screen); + + if (screen->driScreen == NULL) { + LogMessage(X_ERROR, + "AIGLX error: Calling driver entry point failed\n"); + goto handle_error; + } + + screen->base.fbconfigs = glxConvertConfigs(screen->core, + driConfigs, GLX_WINDOW_BIT); + + initializeExtensions(screen); + + DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart, + &screen->texOffsetFinish); + + __glXScreenInit(&screen->base, pScreen); + + /* The first call simply determines the length of the extension string. + * This allows us to allocate some memory to hold the extension string, + * but it requires that we call __glXGetExtensionString a second time. + */ + buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); + if (buffer_size > 0) { + free(screen->base.GLXextensions); + + screen->base.GLXextensions = xnfalloc(buffer_size); + (void) __glXGetExtensionString(screen->glx_enable_bits, + screen->base.GLXextensions); + } + + __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", driverName); + + return &screen->base; + + handle_error: + if (pSAREA != NULL) + drmUnmap(pSAREA, SAREA_MAX); + + if (framebuffer.base != NULL) + drmUnmap((drmAddress)framebuffer.base, framebuffer.size); + + if (fd >= 0) + drmCloseOnce(fd); + + DRICloseConnection(pScreen); + + if (screen->driver) + dlclose(screen->driver); + + free(screen); + + LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); + + return NULL; +} + +_X_EXPORT __GLXprovider __glXDRIProvider = { + __glXDRIscreenProbe, + "DRI", + NULL +}; |