2013-08-23 01:06:53 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013, NVIDIA CORPORATION.
|
2013-08-23 01:14:33 +02:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and/or associated documentation files (the
|
|
|
|
* "Materials"), to deal in the Materials without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sublicense, and/or sell copies of the Materials, and to
|
|
|
|
* permit persons to whom the Materials are furnished to do so, subject to
|
|
|
|
* the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included
|
|
|
|
* unaltered in all copies or substantial portions of the Materials.
|
|
|
|
* Any additions, deletions, or changes to the original source files
|
|
|
|
* must be clearly indicated in accompanying documentation.
|
|
|
|
*
|
|
|
|
* THE MATERIALS ARE 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 THE AUTHORS OR COPYRIGHT HOLDERS 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
|
|
|
|
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
2013-08-23 01:06:53 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
2013-08-23 01:14:33 +02:00
|
|
|
#include <X11/Xlibint.h>
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <string.h>
|
2014-10-03 01:17:59 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
#include "libglxthread.h"
|
2013-08-23 01:16:15 +02:00
|
|
|
#include "libglxabipriv.h"
|
|
|
|
#include "libglxmapping.h"
|
|
|
|
#include "libglxcurrent.h"
|
|
|
|
#include "utils_misc.h"
|
2013-08-23 01:20:01 +02:00
|
|
|
#include "trace.h"
|
2013-08-23 01:14:33 +02:00
|
|
|
#include "GL/glxproto.h"
|
Re-implement libGL such that ELF symbol filtering is optional
Unfortunately, glibc has a bug where dlopening a shared library with
DT_FILTER or DT_AUXILIARY ELF headers can cause the application to
segfault (see https://sourceware.org/bugzilla/show_bug.cgi?id=16272).
Hence, for now, we can't rely on ELF symbol filtering to implement the
libGL compatibility library for libGLdispatch and libGLX. This change
re-implements libGL such that this is no longer necessary, by building
in the glapi static dispatch stubs and implementing thin wrapper
functions around GLX entrypoints.
- Rename getCachedProcAddress() to __glXGetCachedProcAddress() and give
this public visibility. This is used by the libGL wrapper library to
retrieve GLX entrypoints at load time.
- Link libGLX with the -Bsymbolic flag so __glXGetCachedProcAddress()
avoids referencing functions in the libGL wrapper library when libGL
and libGLX are both loaded.
- Replace the hand-coded no-op definitions in libglxnoopdefs.h with
a spec file, glx_funcs.spec, and a simple Perl script, gen_stubs.pl,
which parses the file and generates no-op functions as well as
pass-through functions that are used by libGL.
- Restructure GLdispatch/vnd-glapi/mapi/entry.c such that the pure C
fallback code is in its own header, entry_pure_c.h. In each of the
entry_*.h headers, separate code not related to implementing the
static dispatch stubs into an "#if !defined(STATIC_DISPATCH_ONLY)"
block.
- Give u_current (which is #defined as _glapi_Current or
_glapi_tls_Current depending on the thread storage model used) public
visibility so it can be referenced from outside of libGLdispatch.so.
- When building libGL, include GLdispatch/vnd-glapi/mapi/entry.c in the
sources, and define STATIC_DISPATCH_ONLY so that only the static
entrypoints are compiled. Remove the -Wl,--auxiliary flags from
Makefile.am.
Bonus: fix "make distcheck" by adding GLdispatchABI.h to noinst_HEADERS.
Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
2013-12-03 21:06:47 +01:00
|
|
|
#include "libglxgl.h"
|
2015-10-08 02:56:02 +02:00
|
|
|
#include "glvnd_list.h"
|
2016-04-05 20:58:17 +02:00
|
|
|
#include "app_error_check.h"
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
#include "lkdhash.h"
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
/* current version numbers */
|
|
|
|
#define GLX_MAJOR_VERSION 1
|
|
|
|
#define GLX_MINOR_VERSION 4
|
2016-01-08 21:25:46 +01:00
|
|
|
#define GLX_VERSION_STRING "1.4"
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2018-02-12 18:41:59 +01:00
|
|
|
/*
|
|
|
|
* Older versions of glxproto.h contained a typo where "Attribs" was misspelled.
|
|
|
|
* The typo was fixed in the xorgproto version of glxproto.h, breaking the API.
|
|
|
|
* Work around that here.
|
|
|
|
*/
|
|
|
|
#if !defined(X_GLXCreateContextAttribsARB) && \
|
|
|
|
defined(X_GLXCreateContextAtrribsARB)
|
|
|
|
#define X_GLXCreateContextAttribsARB X_GLXCreateContextAtrribsARB
|
|
|
|
#endif
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
static glvnd_mutex_t clientStringLock = GLVND_MUTEX_INITIALIZER;
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
/**
|
|
|
|
* This structure keeps track of a rendering context.
|
|
|
|
*
|
|
|
|
* It's used both to keep track of which vendor owns each context and for
|
|
|
|
* whether a context is current to any thread.
|
2013-11-21 23:02:20 +01:00
|
|
|
*/
|
2016-02-26 23:04:32 +01:00
|
|
|
struct __GLXcontextInfoRec {
|
2016-02-10 00:50:37 +01:00
|
|
|
GLXContext context;
|
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
int currentCount;
|
|
|
|
Bool deleted;
|
2013-11-21 23:02:20 +01:00
|
|
|
UT_hash_handle hh;
|
2016-02-26 23:04:32 +01:00
|
|
|
};
|
2013-11-21 23:02:20 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
static __GLXcontextInfo *glxContextHash = NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The mutex used to protect the \c glxContextHash hash. Any thread must
|
|
|
|
* take this mutex before it accesses the \c glxContextHash, or before it
|
|
|
|
* modifies any field in a __GLXcontextInfo structure.
|
|
|
|
*
|
|
|
|
* Note that a \c __GLXcontextInfo struct will stay valid for as long as a context
|
|
|
|
* is. That is, it's only freed when the context is deleted and no longer
|
|
|
|
* current to any thread.
|
|
|
|
*
|
|
|
|
* Also note that the \c context and \c vendor values are never modified for
|
|
|
|
* the life of the structure. Thus, it's safe to access them for the current
|
|
|
|
* thread's current context without having to take the \c glxContextHashLock
|
|
|
|
* mutex.
|
|
|
|
*/
|
|
|
|
static glvnd_mutex_t glxContextHashLock;
|
2013-11-21 23:02:20 +01:00
|
|
|
|
2015-10-08 02:56:02 +02:00
|
|
|
/**
|
2016-03-04 21:01:34 +01:00
|
|
|
* A list of current __GLXThreadState structures. This is used so that we can
|
2015-10-08 02:56:02 +02:00
|
|
|
* clean up at process termination or after a fork.
|
|
|
|
*/
|
2016-03-04 21:01:34 +01:00
|
|
|
static struct glvnd_list currentThreadStateList;
|
|
|
|
static glvnd_mutex_t currentThreadStateListMutex = GLVND_MUTEX_INITIALIZER;
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
static __GLXThreadState *CreateThreadState(__GLXvendorInfo *vendor);
|
|
|
|
static void DestroyThreadState(__GLXThreadState *threadState);
|
2016-02-10 00:50:37 +01:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Updates the current context.
|
|
|
|
*
|
|
|
|
* If the old context was flagged for deletion and is no longer current to any
|
|
|
|
* thread, then it will also remove the context from the context hashtable.
|
|
|
|
*
|
|
|
|
* \note glxContextHashLock must be locked before calling this
|
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* \param[in] newCtxInfo The new context to make current, or \c NULL to just
|
|
|
|
* release the current context.
|
|
|
|
* \param[in] oldCtxInfo The previous current context, or \c NULL if no context
|
|
|
|
* was current before.
|
|
|
|
*/
|
|
|
|
static void UpdateCurrentContext(__GLXcontextInfo *newCtxInfo, __GLXcontextInfo *oldCtxInfo);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes and frees an entry from the glxContextHash table.
|
|
|
|
*
|
|
|
|
* The caller must take the \c glxContextHashLock mutex before calling this
|
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* \param ctx The context to free.
|
|
|
|
*/
|
|
|
|
static void FreeContextInfo(__GLXcontextInfo *ctx);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether a rendering context should be deleted.
|
|
|
|
*
|
|
|
|
* If the context is marked for deletion, and is not current to any thread,
|
|
|
|
* then it will remove and free the __GLXcontextInfo struct.
|
|
|
|
*/
|
|
|
|
static void CheckContextDeleted(__GLXcontextInfo *ctx);
|
2014-10-29 21:53:50 +01:00
|
|
|
|
2015-10-15 00:57:17 +02:00
|
|
|
static void __glXSendError(Display *dpy, unsigned char errorCode,
|
|
|
|
XID resourceID, unsigned char minorCode, Bool coreX11error);
|
|
|
|
|
2015-12-18 18:48:14 +01:00
|
|
|
/*!
|
|
|
|
* A common helper for GLX functions that dispatch based on a drawable.
|
|
|
|
*
|
|
|
|
* This function will call __glXThreadInitialize and then look up the vendor
|
|
|
|
* for a drawable.
|
|
|
|
*
|
|
|
|
* If it can't find a vendor for the drawable, then it will call __glXSendError
|
|
|
|
* to generate an error.
|
|
|
|
*
|
|
|
|
* Note that if the server doesn't support the x11glvnd extension, then this
|
|
|
|
* will return the same vendor library whether or not the drawable is valid.
|
|
|
|
* In that case, we'll just rely on the vendor library to report the error if
|
|
|
|
* the drawable is not valid.
|
|
|
|
*
|
|
|
|
* \param dpy The display connection.
|
|
|
|
* \param draw The drawable XID.
|
|
|
|
* \param minorCode The minor opcode of the function being called.
|
|
|
|
* \param errorCode The error code to report if the drawable is invalid.
|
|
|
|
* \param coreX11error True if the error is a core X11 error code, or False if
|
|
|
|
* it's a GLX error code.
|
|
|
|
*/
|
|
|
|
static __GLXvendorInfo *CommonDispatchDrawable(Display *dpy, GLXDrawable draw,
|
|
|
|
unsigned char minorCode, unsigned char errorCode, Bool coreX11error)
|
|
|
|
{
|
|
|
|
__GLXvendorInfo *vendor = NULL;
|
|
|
|
|
|
|
|
if (draw != None) {
|
|
|
|
__glXThreadInitialize();
|
2016-02-26 22:41:30 +01:00
|
|
|
vendor = __glXVendorFromDrawable(dpy, draw);
|
2015-12-18 18:48:14 +01:00
|
|
|
}
|
|
|
|
if (vendor == NULL) {
|
|
|
|
__glXSendError(dpy, errorCode, draw, minorCode, coreX11error);
|
|
|
|
}
|
|
|
|
return vendor;
|
|
|
|
}
|
2014-10-29 21:53:50 +01:00
|
|
|
|
2015-12-18 19:10:35 +01:00
|
|
|
static __GLXvendorInfo *CommonDispatchContext(Display *dpy, GLXContext context,
|
|
|
|
unsigned char minorCode)
|
|
|
|
{
|
|
|
|
__GLXvendorInfo *vendor = NULL;
|
|
|
|
|
|
|
|
if (context != NULL) {
|
|
|
|
__glXThreadInitialize();
|
2016-02-26 22:41:30 +01:00
|
|
|
vendor = __glXVendorFromContext(context);
|
2015-12-18 19:10:35 +01:00
|
|
|
}
|
|
|
|
if (vendor == NULL) {
|
|
|
|
__glXSendError(dpy, GLXBadContext, 0, minorCode, False);
|
|
|
|
}
|
|
|
|
return vendor;
|
|
|
|
}
|
|
|
|
|
2015-12-18 21:25:47 +01:00
|
|
|
static __GLXvendorInfo *CommonDispatchFBConfig(Display *dpy, GLXFBConfig config,
|
2016-01-04 21:20:46 +01:00
|
|
|
unsigned char minorCode)
|
2015-12-18 21:25:47 +01:00
|
|
|
{
|
|
|
|
__GLXvendorInfo *vendor = NULL;
|
|
|
|
|
|
|
|
if (config != NULL) {
|
|
|
|
__glXThreadInitialize();
|
2016-02-26 22:41:30 +01:00
|
|
|
vendor = __glXVendorFromFBConfig(dpy, config);
|
2015-12-18 21:25:47 +01:00
|
|
|
}
|
|
|
|
if (vendor == NULL) {
|
|
|
|
__glXSendError(dpy, GLXBadFBConfig, 0, minorCode, False);
|
|
|
|
}
|
|
|
|
return vendor;
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attrib_list)
|
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, screen);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.chooseVisual(dpy, screen, attrib_list);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXCopyContext(Display *dpy, GLXContext src, GLXContext dst,
|
2013-08-23 01:06:53 +02:00
|
|
|
unsigned long mask)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* GLX requires that src and dst are on the same X screen, but the
|
|
|
|
* application may have passed invalid input. Pick the screen
|
|
|
|
* from one of the contexts, and then let that vendor's
|
|
|
|
* implementation validate that both contexts are on the same
|
|
|
|
* screen.
|
|
|
|
*/
|
2015-12-18 19:10:35 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchContext(dpy, src, X_GLXCopyContext);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.copyContext(dpy, src, dst, mask);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
|
2013-08-23 01:06:53 +02:00
|
|
|
GLXContext share_list, Bool direct)
|
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, vis->screen);
|
2016-01-04 21:05:09 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
GLXContext context = vendor->staticDispatch.createContext(dpy, vis, share_list, direct);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyContext(dpy, context);
|
|
|
|
context = NULL;
|
|
|
|
}
|
2016-01-04 21:05:09 +01:00
|
|
|
return context;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-15 00:57:17 +02:00
|
|
|
PUBLIC GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config,
|
|
|
|
int render_type, GLXContext share_list,
|
|
|
|
Bool direct)
|
|
|
|
{
|
2015-12-18 21:25:47 +01:00
|
|
|
GLXContext context = NULL;
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreateNewContext);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
context = vendor->staticDispatch.createNewContext(dpy, config, render_type,
|
2015-10-15 00:57:17 +02:00
|
|
|
share_list, direct);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyContext(dpy, context);
|
|
|
|
context = NULL;
|
|
|
|
}
|
2015-12-18 21:25:47 +01:00
|
|
|
}
|
2015-10-15 00:57:17 +02:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2017-11-29 22:38:50 +01:00
|
|
|
static GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config,
|
|
|
|
GLXContext share_list, Bool direct, const int *attrib_list)
|
|
|
|
{
|
|
|
|
GLXContext context = NULL;
|
|
|
|
__GLXvendorInfo *vendor = NULL;
|
|
|
|
|
|
|
|
if (attrib_list != NULL) {
|
|
|
|
// See if the caller passed in a GLX_SCREEN attribute, and if so, use
|
|
|
|
// that to select a vendor library. This is needed for
|
|
|
|
// GLX_EXT_no_config_context, where we won't have a GLXFBConfig handle.
|
|
|
|
int i;
|
|
|
|
for (i=0; attrib_list[i] != None; i += 2) {
|
|
|
|
if (attrib_list[i] == GLX_SCREEN) {
|
|
|
|
int screen = attrib_list[i + 1];
|
|
|
|
vendor = __glXGetDynDispatch(dpy, screen);
|
|
|
|
if (vendor == NULL) {
|
|
|
|
__glXSendError(dpy, BadValue, 0,
|
2018-02-12 18:41:59 +01:00
|
|
|
X_GLXCreateContextAttribsARB, True);
|
2017-11-29 22:38:50 +01:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vendor == NULL) {
|
|
|
|
// We didn't get a GLX_SCREEN attribute, so look at the config instead.
|
2018-02-12 18:41:59 +01:00
|
|
|
vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreateContextAttribsARB);
|
2017-11-29 22:38:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vendor != NULL && vendor->staticDispatch.createContextAttribsARB != NULL) {
|
|
|
|
context = vendor->staticDispatch.createContextAttribsARB(dpy, config, share_list, direct, attrib_list);
|
|
|
|
if (context != NULL) {
|
|
|
|
if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyContext(dpy, context);
|
|
|
|
context = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXDestroyContext(Display *dpy, GLXContext context)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-04-05 21:02:02 +02:00
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
|
|
|
|
if (context == NULL) {
|
|
|
|
// Some drivers will just return without generating an error if the app
|
|
|
|
// passes NULL for a context, and unfortunately there are some broken
|
|
|
|
// applications that depend on that behavior.
|
|
|
|
glvndAppErrorCheckReportError("glXDestroyContext called with NULL for context\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vendor = CommonDispatchContext(dpy, context, X_GLXDestroyContext);
|
2015-12-18 19:10:35 +01:00
|
|
|
if (vendor != NULL) {
|
2016-02-10 00:50:37 +01:00
|
|
|
__glXRemoveVendorContextMapping(dpy, context);
|
2015-12-18 19:10:35 +01:00
|
|
|
vendor->staticDispatch.destroyContext(dpy, context);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-15 00:57:17 +02:00
|
|
|
static Bool __glXIsDirect(Display *dpy, __GLXdisplayInfo *dpyInfo, GLXContextID context)
|
|
|
|
{
|
|
|
|
xGLXIsDirectReq *req;
|
|
|
|
xGLXIsDirectReply reply;
|
|
|
|
|
|
|
|
assert(dpyInfo->glxSupported);
|
|
|
|
|
|
|
|
LockDisplay(dpy);
|
|
|
|
|
|
|
|
GetReq(GLXIsDirect, req);
|
|
|
|
req->reqType = dpyInfo->glxMajorOpcode;
|
|
|
|
req->glxCode = X_GLXIsDirect;
|
|
|
|
req->context = context;
|
|
|
|
_XReply(dpy, (xReply *) &reply, 0, False);
|
|
|
|
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
|
|
|
|
return reply.isDirect;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds the screen number for a context, using the context's XID. This
|
|
|
|
* function sends the request directly, so it doesn't rely on any vendor
|
|
|
|
* library.
|
|
|
|
*
|
|
|
|
* Adapted from Mesa's glXImportContextEXT implementation.
|
|
|
|
*/
|
|
|
|
static int __glXGetScreenForContextID(Display *dpy, __GLXdisplayInfo *dpyInfo,
|
|
|
|
GLXContextID contextID)
|
|
|
|
{
|
|
|
|
xGLXQueryContextReply reply;
|
|
|
|
int *propList;
|
|
|
|
int majorVersion, minorVersion;
|
|
|
|
int screen = -1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(dpyInfo->glxSupported);
|
|
|
|
|
|
|
|
// Check the version number so that we know which request to send.
|
|
|
|
if (!glXQueryVersion(dpy, &majorVersion, &minorVersion)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send the glXQueryContextInfoEXT request */
|
|
|
|
LockDisplay(dpy);
|
|
|
|
|
|
|
|
if (majorVersion > 1 || minorVersion >= 3) {
|
|
|
|
xGLXQueryContextReq *req;
|
|
|
|
|
|
|
|
GetReq(GLXQueryContext, req);
|
|
|
|
|
|
|
|
req->reqType = dpyInfo->glxMajorOpcode;
|
|
|
|
req->glxCode = X_GLXQueryContext;
|
|
|
|
req->context = contextID;
|
|
|
|
} else {
|
|
|
|
xGLXVendorPrivateReq *vpreq;
|
|
|
|
xGLXQueryContextInfoEXTReq *req;
|
|
|
|
|
|
|
|
GetReqExtra(GLXVendorPrivate,
|
|
|
|
sz_xGLXQueryContextInfoEXTReq - sz_xGLXVendorPrivateReq,
|
|
|
|
vpreq);
|
|
|
|
req = (xGLXQueryContextInfoEXTReq *) vpreq;
|
|
|
|
req->reqType = dpyInfo->glxMajorOpcode;
|
|
|
|
req->glxCode = X_GLXVendorPrivateWithReply;
|
|
|
|
req->vendorCode = X_GLXvop_QueryContextInfoEXT;
|
|
|
|
req->context = contextID;
|
|
|
|
}
|
|
|
|
|
|
|
|
_XReply(dpy, (xReply *) &reply, 0, False);
|
|
|
|
|
|
|
|
if (reply.n <= 0) {
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
propList = malloc(reply.n * 8);
|
|
|
|
if (propList == NULL) {
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
_XRead(dpy, (char *) propList, reply.n * 8);
|
|
|
|
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
|
|
|
|
for (i=0; i<reply.n; i++) {
|
|
|
|
int *prop = &propList[i * 2];
|
|
|
|
if (prop[0] == GLX_SCREEN) {
|
|
|
|
screen = prop[1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(propList);
|
|
|
|
return screen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLXContext glXImportContextEXT(Display *dpy, GLXContextID contextID)
|
|
|
|
{
|
|
|
|
__GLXdisplayInfo *dpyInfo;
|
|
|
|
int screen;
|
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
|
|
|
|
dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo == NULL || !dpyInfo->glxSupported) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The GLX_EXT_import_context spec says:
|
|
|
|
*
|
|
|
|
* "If <contextID> does not refer to a valid context, then a BadContext
|
|
|
|
* error is generated; if <contextID> refers to direct rendering
|
|
|
|
* context then no error is generated but glXImportContextEXT returns
|
|
|
|
* NULL."
|
|
|
|
*
|
|
|
|
* If contextID is None, generate BadContext on the client-side. Other
|
|
|
|
* sorts of invalid contexts will be detected by the server in the
|
|
|
|
* __glXIsDirect call.
|
|
|
|
*/
|
|
|
|
if (contextID == None) {
|
|
|
|
__glXSendError(dpy, GLXBadContext, contextID, X_GLXIsDirect, False);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__glXIsDirect(dpy, dpyInfo, contextID)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the screen number for the context. We can't rely on a vendor
|
|
|
|
// library yet, so send the request manually.
|
|
|
|
screen = __glXGetScreenForContextID(dpy, dpyInfo, contextID);
|
|
|
|
if (screen < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vendor = __glXLookupVendorByScreen(dpy, screen);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (vendor != NULL && vendor->staticDispatch.importContextEXT != NULL
|
|
|
|
&& vendor->staticDispatch.freeContextEXT) {
|
2015-10-15 00:57:17 +02:00
|
|
|
GLXContext context = vendor->staticDispatch.importContextEXT(dpy, contextID);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.freeContextEXT(dpy, context);
|
|
|
|
context = NULL;
|
|
|
|
}
|
2015-10-15 00:57:17 +02:00
|
|
|
return context;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void glXFreeContextEXT(Display *dpy, GLXContext context)
|
|
|
|
{
|
2015-12-18 19:10:35 +01:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2015-10-15 00:57:17 +02:00
|
|
|
|
2015-12-18 19:10:35 +01:00
|
|
|
__glXThreadInitialize();
|
2015-10-15 00:57:17 +02:00
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
vendor = __glXVendorFromContext(context);
|
2015-10-15 00:57:17 +02:00
|
|
|
if (vendor != NULL && vendor->staticDispatch.freeContextEXT != NULL) {
|
2016-02-10 00:50:37 +01:00
|
|
|
__glXRemoveVendorContextMapping(dpy, context);
|
2015-10-15 00:57:17 +02:00
|
|
|
vendor->staticDispatch.freeContextEXT(dpy, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *vis, Pixmap pixmap)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, vis->screen);
|
2016-01-04 20:37:08 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
GLXPixmap pmap = vendor->staticDispatch.createGLXPixmap(dpy, vis, pixmap);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorDrawableMapping(dpy, pmap, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyGLXPixmap(dpy, pmap);
|
|
|
|
pmap = None;
|
|
|
|
}
|
2016-01-04 20:37:08 +01:00
|
|
|
return pmap;
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pix)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, pix,
|
|
|
|
X_GLXDestroyGLXPixmap, GLXBadPixmap, False);
|
|
|
|
if (vendor != NULL) {
|
2016-01-04 20:37:08 +01:00
|
|
|
__glXRemoveVendorDrawableMapping(dpy, pix);
|
2015-12-18 18:48:14 +01:00
|
|
|
vendor->staticDispatch.destroyGLXPixmap(dpy, pix);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC int glXGetConfig(Display *dpy, XVisualInfo *vis, int attrib, int *value)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor;
|
2014-10-03 01:17:59 +02:00
|
|
|
|
2016-05-04 18:36:11 +02:00
|
|
|
__glXThreadInitialize();
|
2013-11-18 23:13:58 +01:00
|
|
|
|
|
|
|
if (!dpy || !vis || !value) {
|
|
|
|
return GLX_BAD_VALUE;
|
|
|
|
}
|
|
|
|
|
2016-05-04 18:36:11 +02:00
|
|
|
vendor = __glXLookupVendorByScreen(dpy, vis->screen);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.getConfig(dpy, vis, attrib, value);
|
|
|
|
} else {
|
|
|
|
return GLX_BAD_VALUE;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXContext glXGetCurrentContext(void)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
|
|
|
if (threadState != NULL) {
|
|
|
|
// The current thread has a thread state pointer if and only if it has a
|
2016-02-10 00:50:37 +01:00
|
|
|
// current context, and the currentContext pointer is assigned before
|
2016-03-04 21:01:34 +01:00
|
|
|
// the threadState pointer is put into TLS, so it will never be NULL.
|
|
|
|
assert(threadState->currentContext != NULL);
|
|
|
|
return threadState->currentContext->context;
|
2016-02-10 00:50:37 +01:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXDrawable glXGetCurrentDrawable(void)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
|
|
|
if (threadState != NULL) {
|
|
|
|
return threadState->currentDraw;
|
2015-10-08 02:56:02 +02:00
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC GLXDrawable glXGetCurrentReadDrawable(void)
|
|
|
|
{
|
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
|
|
|
if (threadState != NULL) {
|
|
|
|
return threadState->currentRead;
|
2015-10-08 02:56:02 +02:00
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC Display *glXGetCurrentDisplay(void)
|
|
|
|
{
|
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
|
|
|
if (threadState != NULL) {
|
|
|
|
return threadState->currentDisplay;
|
2015-10-08 02:56:02 +02:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-08 02:56:02 +02:00
|
|
|
__GLXvendorInfo *__glXGetCurrentDynDispatch(void)
|
|
|
|
{
|
2016-01-21 23:08:26 +01:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
if (threadState != NULL) {
|
|
|
|
return threadState->currentVendor;
|
2015-10-08 02:56:02 +02:00
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC Bool glXIsDirect(Display *dpy, GLXContext context)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 19:10:35 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchContext(dpy, context, X_GLXIsDirect);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.isDirect(dpy, context);
|
|
|
|
} else {
|
|
|
|
return False;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-03-07 22:52:08 +01:00
|
|
|
void __glXDisplayClosed(__GLXdisplayInfo *dpyInfo)
|
2013-11-25 23:47:32 +01:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState;
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState = __glXGetCurrentThreadState();
|
2016-03-29 01:44:05 +02:00
|
|
|
if (threadState != NULL && threadState->currentDisplay == dpyInfo->dpy) {
|
2015-10-08 02:56:02 +02:00
|
|
|
// Clear out the current context, but don't call into the vendor
|
|
|
|
// library or do anything that might require a valid display.
|
|
|
|
__glDispatchLoseCurrent();
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
2016-03-04 21:01:34 +01:00
|
|
|
UpdateCurrentContext(NULL, threadState->currentContext);
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2016-03-04 21:01:34 +01:00
|
|
|
DestroyThreadState(threadState);
|
2015-10-08 02:56:02 +02:00
|
|
|
}
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(¤tThreadStateListMutex);
|
|
|
|
glvnd_list_for_each_entry(threadState, ¤tThreadStateList, entry) {
|
2013-11-25 23:47:32 +01:00
|
|
|
/*
|
2016-03-04 21:01:34 +01:00
|
|
|
* Stub out any references to this display in any other thread states.
|
2013-11-25 23:47:32 +01:00
|
|
|
*/
|
2016-03-29 01:44:05 +02:00
|
|
|
if (threadState->currentDisplay == dpyInfo->dpy) {
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState->currentDisplay = NULL;
|
2013-11-25 23:47:32 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-04 21:01:34 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(¤tThreadStateListMutex);
|
2013-11-25 23:47:32 +01:00
|
|
|
}
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
static void ThreadDestroyed(__GLdispatchThreadState *threadState)
|
2015-06-05 23:23:42 +02:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *glxState = (__GLXThreadState *) threadState;
|
2015-06-05 23:23:42 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
// Clear out the current context.
|
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
2015-06-24 22:50:31 +02:00
|
|
|
UpdateCurrentContext(NULL, glxState->currentContext);
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2015-06-05 23:23:42 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
// Free the thread state struct.
|
|
|
|
DestroyThreadState(glxState);
|
2015-06-05 23:23:42 +02:00
|
|
|
}
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
static __GLXThreadState *CreateThreadState(__GLXvendorInfo *vendor)
|
2013-08-12 22:12:09 +02:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = calloc(1, sizeof(*threadState));
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
assert(threadState);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState->glas.tag = GLDISPATCH_API_GLX;
|
|
|
|
threadState->glas.threadDestroyedCallback = ThreadDestroyed;
|
|
|
|
threadState->currentVendor = vendor;
|
2014-01-24 04:51:49 +01:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(¤tThreadStateListMutex);
|
|
|
|
glvnd_list_add(&threadState->entry, ¤tThreadStateList);
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(¤tThreadStateListMutex);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
return threadState;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
static void DestroyThreadState(__GLXThreadState *threadState)
|
2013-08-12 22:12:09 +02:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
// Free the thread state struct.
|
|
|
|
__glvndPthreadFuncs.mutex_lock(¤tThreadStateListMutex);
|
|
|
|
glvnd_list_del(&threadState->entry);
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(¤tThreadStateListMutex);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
free(threadState);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2013-11-24 23:01:49 +01:00
|
|
|
/*
|
|
|
|
* Notifies libglvnd that the given context has been marked for destruction
|
|
|
|
* by glXDestroyContext(), and removes any context -> screen mappings if
|
|
|
|
* necessary.
|
|
|
|
*/
|
2016-02-10 00:50:37 +01:00
|
|
|
void __glXRemoveVendorContextMapping(Display *dpy, GLXContext context)
|
2013-11-24 23:01:49 +01:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *ctxInfo;
|
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(glxContextHash, &context, ctxInfo);
|
|
|
|
if (ctxInfo != NULL) {
|
|
|
|
ctxInfo->deleted = True;
|
|
|
|
CheckContextDeleted(ctxInfo);
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
2016-02-26 22:05:38 +01:00
|
|
|
int __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorInfo *vendor)
|
2013-11-24 23:01:49 +01:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *ctxInfo;
|
2014-10-29 21:53:50 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
2013-11-21 23:02:20 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(glxContextHash, &context, ctxInfo);
|
|
|
|
if (ctxInfo == NULL) {
|
|
|
|
ctxInfo = (__GLXcontextInfo *) malloc(sizeof(__GLXcontextInfo));
|
2016-02-26 22:05:38 +01:00
|
|
|
if (ctxInfo == NULL) {
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
ctxInfo->context = context;
|
|
|
|
ctxInfo->vendor = vendor;
|
|
|
|
ctxInfo->currentCount = 0;
|
|
|
|
ctxInfo->deleted = False;
|
|
|
|
HASH_ADD_PTR(glxContextHash, context, ctxInfo);
|
|
|
|
} else {
|
2016-02-26 22:05:38 +01:00
|
|
|
if (ctxInfo->vendor != vendor) {
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2016-02-26 22:05:38 +01:00
|
|
|
return 0;
|
2016-02-10 00:50:37 +01:00
|
|
|
}
|
2015-06-24 22:50:31 +02:00
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
__GLXvendorInfo *__glXVendorFromContext(GLXContext context)
|
2016-02-10 00:50:37 +01:00
|
|
|
{
|
|
|
|
__GLXcontextInfo *ctxInfo;
|
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
|
|
|
HASH_FIND_PTR(glxContextHash, &context, ctxInfo);
|
|
|
|
if (ctxInfo != NULL) {
|
|
|
|
vendor = ctxInfo->vendor;
|
2014-10-29 21:53:50 +01:00
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
return vendor;
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
static void FreeContextInfo(__GLXcontextInfo *ctx)
|
2013-11-24 23:01:49 +01:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
if (ctx != NULL) {
|
|
|
|
HASH_DELETE(hh, glxContextHash, ctx);
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
static void UpdateCurrentContext(__GLXcontextInfo *newCtxInfo, __GLXcontextInfo *oldCtxInfo)
|
|
|
|
{
|
|
|
|
if (newCtxInfo == oldCtxInfo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (newCtxInfo != NULL) {
|
|
|
|
newCtxInfo->currentCount++;
|
|
|
|
}
|
|
|
|
if (oldCtxInfo != NULL) {
|
|
|
|
assert(oldCtxInfo->currentCount > 0);
|
|
|
|
oldCtxInfo->currentCount--;
|
|
|
|
CheckContextDeleted(oldCtxInfo);
|
|
|
|
}
|
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
static void CheckContextDeleted(__GLXcontextInfo *ctx)
|
|
|
|
{
|
|
|
|
if (ctx->deleted && ctx->currentCount == 0) {
|
|
|
|
FreeContextInfo(ctx);
|
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
static void __glXSendError(Display *dpy, unsigned char errorCode,
|
|
|
|
XID resourceID, unsigned char minorCode, Bool coreX11error)
|
2013-11-24 23:01:49 +01:00
|
|
|
{
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = NULL;
|
|
|
|
xError error;
|
2014-10-29 22:08:38 +01:00
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
if (dpy == NULL) {
|
|
|
|
return;
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
dpyInfo = __glXLookupDisplay(dpy);
|
2013-11-24 23:01:49 +01:00
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
if (dpyInfo == NULL || !dpyInfo->glxSupported) {
|
|
|
|
return;
|
2014-10-29 22:08:38 +01:00
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
LockDisplay(dpy);
|
|
|
|
|
|
|
|
error.type = X_Error;
|
|
|
|
error.errorCode = errorCode;
|
|
|
|
error.sequenceNumber = dpy->request;
|
|
|
|
error.resourceID = resourceID;
|
|
|
|
error.minorCode = minorCode;
|
|
|
|
error.majorCode = dpyInfo->glxMajorOpcode;
|
|
|
|
if (!coreX11error) {
|
|
|
|
error.errorCode += dpyInfo->glxFirstError;
|
2014-10-29 22:08:38 +01:00
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
_XError(dpy, &error);
|
|
|
|
|
|
|
|
UnlockDisplay(dpy);
|
2014-10-29 22:08:38 +01:00
|
|
|
}
|
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
static void NotifyXError(Display *dpy, unsigned char errorCode,
|
|
|
|
XID resourceID, unsigned char minorCode, Bool coreX11error,
|
|
|
|
__GLXvendorInfo *vendor)
|
2014-10-29 22:08:38 +01:00
|
|
|
{
|
2015-08-29 00:50:42 +02:00
|
|
|
if (vendor != NULL && vendor->glxvc->notifyError != NULL) {
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
Bool ret = vendor->glxvc->notifyError(dpy, errorCode, resourceID,
|
|
|
|
minorCode, coreX11error);
|
|
|
|
if (!ret) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
__glXSendError(dpy, errorCode, resourceID, minorCode, coreX11error);
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
2015-10-08 02:56:02 +02:00
|
|
|
static Bool InternalLoseCurrent(void)
|
2013-08-12 22:12:09 +02:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState = __glXGetCurrentThreadState();
|
2013-08-12 22:12:09 +02:00
|
|
|
Bool ret;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
if (threadState == NULL) {
|
2015-06-19 21:27:08 +02:00
|
|
|
return True;
|
|
|
|
}
|
2014-10-29 22:08:38 +01:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
ret = threadState->currentVendor->staticDispatch.makeCurrent(threadState->currentDisplay, None, NULL);
|
2015-06-19 21:27:08 +02:00
|
|
|
if (!ret) {
|
2014-10-29 22:08:38 +01:00
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
__glDispatchLoseCurrent();
|
|
|
|
|
2015-06-24 22:50:31 +02:00
|
|
|
// Remove the context from the current context map.
|
2016-03-04 21:01:34 +01:00
|
|
|
UpdateCurrentContext(NULL, threadState->currentContext);
|
|
|
|
DestroyThreadState(threadState);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
return True;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
/**
|
|
|
|
* Calls into the vendor library to set the current context, and then updates
|
2016-03-04 21:01:34 +01:00
|
|
|
* the thread state fields to match.
|
2015-06-19 21:27:08 +02:00
|
|
|
*
|
|
|
|
* This function does *not* call into libGLdispatch, so it can only switch
|
|
|
|
* to another context with the same vendor.
|
|
|
|
*
|
|
|
|
* If this function succeeds, then it will update the current display, context,
|
2016-03-04 21:01:34 +01:00
|
|
|
* and drawables in \p threadState.
|
2015-06-19 21:27:08 +02:00
|
|
|
*
|
2016-03-04 21:01:34 +01:00
|
|
|
* If it fails, then it will leave \p threadState unmodified. It's up to the
|
2015-06-19 21:27:08 +02:00
|
|
|
* vendor library to ensure that the old context is still current in that case.
|
|
|
|
*/
|
|
|
|
static Bool InternalMakeCurrentVendor(
|
|
|
|
Display *dpy, GLXDrawable draw, GLXDrawable read,
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *ctxInfo, char callerOpcode,
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState,
|
2015-06-19 21:27:08 +02:00
|
|
|
__GLXvendorInfo *vendor)
|
|
|
|
{
|
|
|
|
Bool ret;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
assert(threadState->currentVendor == vendor);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (callerOpcode == X_GLXMakeCurrent && draw == read) {
|
2016-02-10 00:50:37 +01:00
|
|
|
ret = vendor->staticDispatch.makeCurrent(dpy, draw, ctxInfo->context);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
2015-08-29 00:50:42 +02:00
|
|
|
ret = vendor->staticDispatch.makeContextCurrent(dpy,
|
2015-06-19 21:27:08 +02:00
|
|
|
draw,
|
|
|
|
read,
|
2016-02-10 00:50:37 +01:00
|
|
|
ctxInfo->context);
|
2015-06-19 21:27:08 +02:00
|
|
|
}
|
2014-01-24 04:51:49 +01:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (ret) {
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState->currentDisplay = dpy;
|
|
|
|
threadState->currentDraw = draw;
|
|
|
|
threadState->currentRead = read;
|
|
|
|
threadState->currentContext = ctxInfo;
|
2015-06-19 21:27:08 +02:00
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
/**
|
|
|
|
* Makes a context current. This function handles both the vendor library and
|
|
|
|
* libGLdispatch.
|
|
|
|
*
|
2016-03-04 21:01:34 +01:00
|
|
|
* There must not be a current thread state in libGLdispatch when this function
|
|
|
|
* is called.
|
2015-06-19 21:27:08 +02:00
|
|
|
*
|
|
|
|
* If this function fails, then it will release the context and dispatch state
|
|
|
|
* before returning.
|
|
|
|
*/
|
|
|
|
static Bool InternalMakeCurrentDispatch(
|
|
|
|
Display *dpy, GLXDrawable draw, GLXDrawable read,
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *ctxInfo, char callerOpcode,
|
2015-06-19 21:27:08 +02:00
|
|
|
__GLXvendorInfo *vendor)
|
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState;
|
2015-06-19 21:27:08 +02:00
|
|
|
Bool ret;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
assert(__glXGetCurrentThreadState() == NULL);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
UpdateCurrentContext(ctxInfo, NULL);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState = CreateThreadState(vendor);
|
|
|
|
if (threadState == NULL) {
|
2016-02-10 00:50:37 +01:00
|
|
|
UpdateCurrentContext(NULL, ctxInfo);
|
2015-10-08 02:56:02 +02:00
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
ret = __glDispatchMakeCurrent(
|
2016-03-04 21:01:34 +01:00
|
|
|
&threadState->glas,
|
2015-06-19 21:27:08 +02:00
|
|
|
vendor->glDispatch,
|
|
|
|
vendor->vendorID,
|
2016-03-11 00:36:45 +01:00
|
|
|
vendor->patchCallbacks
|
2015-06-19 21:27:08 +02:00
|
|
|
);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (ret) {
|
2015-10-08 02:56:02 +02:00
|
|
|
// Call into the vendor library.
|
2016-02-10 00:50:37 +01:00
|
|
|
ret = InternalMakeCurrentVendor(dpy, draw, read, ctxInfo, callerOpcode,
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState, vendor);
|
2015-06-19 21:27:08 +02:00
|
|
|
if (!ret) {
|
|
|
|
__glDispatchLoseCurrent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret) {
|
2016-03-04 21:01:34 +01:00
|
|
|
DestroyThreadState(threadState);
|
2016-02-10 00:50:37 +01:00
|
|
|
UpdateCurrentContext(NULL, ctxInfo);
|
2014-01-24 04:51:49 +01:00
|
|
|
}
|
2015-06-19 21:27:08 +02:00
|
|
|
|
|
|
|
return ret;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2015-06-05 19:05:21 +02:00
|
|
|
/**
|
|
|
|
* A common function to handle glXMakeCurrent and glXMakeContextCurrent.
|
|
|
|
*/
|
|
|
|
static Bool CommonMakeCurrent(Display *dpy, GLXDrawable draw,
|
|
|
|
GLXDrawable read, GLXContext context,
|
|
|
|
char callerOpcode)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState;
|
2015-06-19 21:27:08 +02:00
|
|
|
__GLXvendorInfo *oldVendor, *newVendor;
|
|
|
|
Display *oldDpy;
|
2013-08-12 22:12:09 +02:00
|
|
|
GLXDrawable oldDraw, oldRead;
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *oldCtxInfo;
|
|
|
|
__GLXcontextInfo *newCtxInfo;
|
2015-06-19 21:27:08 +02:00
|
|
|
Bool ret;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-12-02 19:52:26 +01:00
|
|
|
__glXThreadInitialize();
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState = __glXGetCurrentThreadState();
|
2015-06-19 21:27:08 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
if (threadState != NULL) {
|
|
|
|
oldVendor = threadState->currentVendor;
|
|
|
|
oldDpy = threadState->currentDisplay;
|
|
|
|
oldDraw = threadState->currentDraw;
|
|
|
|
oldRead = threadState->currentRead;
|
|
|
|
oldCtxInfo = threadState->currentContext;
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
assert(oldCtxInfo != NULL);
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
if (dpy == oldDpy && context == oldCtxInfo->context
|
2015-10-08 02:56:02 +02:00
|
|
|
&& draw == oldDraw && read == oldRead) {
|
|
|
|
// The current display, context, and drawables are the same, so just
|
|
|
|
// return.
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
} else {
|
2016-01-18 20:15:38 +01:00
|
|
|
// We might have a non-GLX context current...
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLdispatchThreadState *glas = __glDispatchGetCurrentThreadState();
|
2016-01-18 20:15:38 +01:00
|
|
|
if (glas != NULL && glas->tag != GLDISPATCH_API_GLX) {
|
|
|
|
NotifyXError(dpy, BadAccess, 0, callerOpcode, True, NULL);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2015-10-08 02:56:02 +02:00
|
|
|
// We don't have a current context already.
|
|
|
|
oldVendor = NULL;
|
|
|
|
oldDpy = NULL;
|
|
|
|
oldDraw = oldRead = None;
|
2016-02-10 00:50:37 +01:00
|
|
|
oldCtxInfo = NULL;
|
2015-06-05 19:05:21 +02:00
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
libGLX: Add support for reporting X errors.
libGLX will now report any X errors that it generates directly, instead of
relying on a vendor library to report them.
For simply reporting errors, the notifyError callback in every vendor library
is functionally identical, so there's no reason to require every vendor to
implement it.
As a notification, it falls apart in glXMakeContextCurrent, which could have
two different vendor libraries if the drawables are on different screens. In
that case, libGLX has to arbitrarily pick one vendor to notify.
Add a __glXSendError function to libglx.c (based on the same function from
Mesa) to report X errors.
The __GLXapiImports::notifyError callback no longer has to report the X error.
It's mostly a notificaiton, although it returns a boolean value to tell libGLX
whether to report or ignore the error.
In glXMakeCurrent/glXMakeContextCurrent, it will report an error to whatever
vendor library owns the current context (if any), instead of the vendor
libraries for the two drawables. The rest of the function looks to the context
to select a vendor, and the old context is the only one that's valid in this
case.
2015-09-29 00:57:09 +02:00
|
|
|
/*
|
|
|
|
* If <ctx> is NULL and <draw> and <read> are not None, or if <draw> or
|
|
|
|
* <read> are set to None and <ctx> is not NULL, then a BadMatch error will
|
|
|
|
* be generated. GLX 1.4 section 3.3.7 (p. 27).
|
|
|
|
*
|
|
|
|
* However, GLX_ARB_create_context specifies that GL 3.0+ contexts may be
|
|
|
|
* made current without a default framebuffer, so the "or if..." part above
|
|
|
|
* is ignored here.
|
|
|
|
*/
|
|
|
|
if (!context && (draw != None || read != None)) {
|
|
|
|
// Notify the vendor library and send the X error. Since we don't have
|
|
|
|
// a new context, instead notify the vendor library that owns the
|
|
|
|
// current context (if there is one).
|
|
|
|
|
|
|
|
NotifyXError(dpy, BadMatch, 0, callerOpcode, True, oldVendor);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
if (oldCtxInfo == NULL && context == NULL) {
|
2015-12-02 19:52:26 +01:00
|
|
|
// If both the old and new contexts are NULL, then there's nothing to
|
|
|
|
// do. Just return early.
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxContextHashLock);
|
2013-11-24 23:01:49 +01:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (context != NULL) {
|
2016-08-04 19:18:17 +02:00
|
|
|
// Look up the new display. This will ensure that we keep track of it
|
|
|
|
// and get a callback when it's closed.
|
|
|
|
if (__glXLookupDisplay(dpy) == NULL) {
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(glxContextHash, &context, newCtxInfo);
|
|
|
|
if (newCtxInfo == NULL) {
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2015-12-18 19:10:35 +01:00
|
|
|
|
2013-11-24 23:01:49 +01:00
|
|
|
/*
|
2015-12-18 19:10:35 +01:00
|
|
|
* We can run into this corner case if a GLX client calls
|
2015-06-19 21:27:08 +02:00
|
|
|
* glXDestroyContext() on a current context, loses current to this
|
|
|
|
* context (causing it to be freed), then tries to make current to the
|
|
|
|
* context again. This is incorrect application behavior, but we should
|
|
|
|
* attempt to handle this failure gracefully.
|
2013-11-24 23:01:49 +01:00
|
|
|
*/
|
2015-12-18 19:10:35 +01:00
|
|
|
NotifyXError(dpy, GLXBadContext, 0, callerOpcode, False, oldVendor);
|
2013-11-24 23:01:49 +01:00
|
|
|
return False;
|
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
newVendor = newCtxInfo->vendor;
|
2015-06-19 21:27:08 +02:00
|
|
|
assert(newVendor != NULL);
|
|
|
|
} else {
|
2016-02-10 00:50:37 +01:00
|
|
|
newCtxInfo = NULL;
|
2015-06-19 21:27:08 +02:00
|
|
|
newVendor = NULL;
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (oldVendor == newVendor) {
|
2016-03-04 21:01:34 +01:00
|
|
|
assert(threadState != NULL);
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
/*
|
|
|
|
* We're switching between two contexts that use the same vendor. That
|
|
|
|
* means the dispatch table is also the same, which is the only thing
|
|
|
|
* that libGLdispatch cares about. Call into the vendor library to
|
|
|
|
* switch contexts, but don't call into libGLdispatch.
|
|
|
|
*/
|
2016-02-10 00:50:37 +01:00
|
|
|
ret = InternalMakeCurrentVendor(dpy, draw, read, newCtxInfo, callerOpcode,
|
2016-03-04 21:01:34 +01:00
|
|
|
threadState, newVendor);
|
2015-06-19 21:27:08 +02:00
|
|
|
if (ret) {
|
2016-02-10 00:50:37 +01:00
|
|
|
UpdateCurrentContext(newCtxInfo, oldCtxInfo);
|
2015-06-19 21:27:08 +02:00
|
|
|
}
|
|
|
|
} else if (newVendor == NULL) {
|
2013-11-24 23:01:49 +01:00
|
|
|
/*
|
2015-06-19 21:27:08 +02:00
|
|
|
* We have a current context and we're releasing it.
|
2013-11-24 23:01:49 +01:00
|
|
|
*/
|
2015-06-19 21:27:08 +02:00
|
|
|
assert(context == NULL);
|
2015-10-08 02:56:02 +02:00
|
|
|
ret = InternalLoseCurrent();
|
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
} else if (oldVendor == NULL) {
|
|
|
|
/*
|
|
|
|
* We don't have a current context, so we only need to make the new one
|
|
|
|
* current.
|
|
|
|
*/
|
2016-02-10 00:50:37 +01:00
|
|
|
ret = InternalMakeCurrentDispatch(dpy, draw, read, newCtxInfo, callerOpcode,
|
2015-10-08 02:56:02 +02:00
|
|
|
newVendor);
|
2015-06-19 21:27:08 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're switching between contexts with different vendors.
|
|
|
|
*
|
|
|
|
* This gets tricky because we have to call into both vendor libraries
|
|
|
|
* and libGLdispatch. Any of those can fail, and if it does, then we
|
|
|
|
* have to make sure libGLX, libGLdispatch, and the vendor libraries
|
|
|
|
* all agree on what the current context is.
|
|
|
|
*
|
|
|
|
* To do that, we'll first release the current context, and then make
|
|
|
|
* the new context current.
|
|
|
|
*/
|
2016-02-10 00:50:37 +01:00
|
|
|
|
|
|
|
// First, check to see if calling InternalLoseCurrent is going to
|
|
|
|
// destroy the old context.
|
|
|
|
Bool canRestoreOldContext = True;
|
|
|
|
if (oldCtxInfo->deleted && oldCtxInfo->currentCount == 1) {
|
|
|
|
canRestoreOldContext = False;
|
|
|
|
}
|
2015-10-08 02:56:02 +02:00
|
|
|
ret = InternalLoseCurrent();
|
|
|
|
|
2015-06-19 21:27:08 +02:00
|
|
|
if (ret) {
|
2016-02-10 00:50:37 +01:00
|
|
|
ret = InternalMakeCurrentDispatch(dpy, draw, read, newCtxInfo, callerOpcode,
|
2015-10-08 02:56:02 +02:00
|
|
|
newVendor);
|
2016-02-10 00:50:37 +01:00
|
|
|
if (!ret && canRestoreOldContext) {
|
2015-06-19 21:27:08 +02:00
|
|
|
/*
|
|
|
|
* Try to restore the old context. Note that this can fail if
|
|
|
|
* the old context was marked for deletion. If that happens,
|
|
|
|
* then we'll end up with no current context instead, but we
|
|
|
|
* should at least still be in a consistent state.
|
|
|
|
*/
|
2016-02-10 00:50:37 +01:00
|
|
|
InternalMakeCurrentDispatch(oldDpy, oldDraw, oldRead, oldCtxInfo,
|
2015-10-08 02:56:02 +02:00
|
|
|
callerOpcode, oldVendor);
|
2015-06-19 21:27:08 +02:00
|
|
|
}
|
2013-11-24 23:01:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
2013-08-12 22:12:09 +02:00
|
|
|
return ret;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2015-06-05 19:05:21 +02:00
|
|
|
PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext context)
|
|
|
|
{
|
|
|
|
return CommonMakeCurrent(dpy, drawable, drawable, context, X_GLXMakeCurrent);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw,
|
|
|
|
GLXDrawable read, GLXContext context)
|
|
|
|
{
|
|
|
|
return CommonMakeCurrent(dpy, draw, read, context, X_GLXMakeContextCurrent);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC Bool glXQueryExtension(Display *dpy, int *error_base, int *event_base)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2013-08-23 01:06:53 +02:00
|
|
|
/*
|
|
|
|
* There isn't enough information to dispatch to a vendor's
|
|
|
|
* implementation, so handle the request here.
|
|
|
|
*/
|
|
|
|
int major, event, error;
|
|
|
|
Bool ret = XQueryExtension(dpy, "GLX", &major, &event, &error);
|
|
|
|
if (ret) {
|
|
|
|
if (error_base) {
|
|
|
|
*error_base = error;
|
|
|
|
}
|
|
|
|
if (event_base) {
|
|
|
|
*event_base = event;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC Bool glXQueryVersion(Display *dpy, int *major, int *minor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* There isn't enough information to dispatch to a vendor's
|
|
|
|
* implementation, so handle the request here.
|
|
|
|
*
|
|
|
|
* Adapted from mesa's
|
|
|
|
*
|
|
|
|
* gallium/state_trackers/egl/x11/glxinit.c:QueryVersion()
|
|
|
|
*
|
|
|
|
* TODO: Mesa's GLX state tracker uses xcb-glx rather than Xlib to perform
|
|
|
|
* the query. Should we do the same here?
|
|
|
|
*/
|
|
|
|
xGLXQueryVersionReq *req;
|
|
|
|
xGLXQueryVersionReply reply;
|
2015-09-28 23:55:57 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
Bool ret;
|
|
|
|
|
2015-09-28 23:55:57 +02:00
|
|
|
dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo == NULL || !dpyInfo->glxSupported) {
|
2013-08-12 22:12:09 +02:00
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockDisplay(dpy);
|
|
|
|
GetReq(GLXQueryVersion, req);
|
2015-09-28 23:55:57 +02:00
|
|
|
req->reqType = dpyInfo->glxMajorOpcode;
|
2013-08-12 22:12:09 +02:00
|
|
|
req->glxCode = X_GLXQueryVersion;
|
|
|
|
req->majorVersion = GLX_MAJOR_VERSION;
|
|
|
|
req->minorVersion = GLX_MINOR_VERSION;
|
|
|
|
|
|
|
|
ret = _XReply(dpy, (xReply *)&reply, 0, False);
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reply.majorVersion != GLX_MAJOR_VERSION) {
|
|
|
|
/* Server does not support same major as client */
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (major) {
|
|
|
|
*major = reply.majorVersion;
|
|
|
|
}
|
|
|
|
if (minor) {
|
|
|
|
*minor = reply.minorVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
return True;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, drawable,
|
|
|
|
X_GLXSwapBuffers, GLXBadDrawable, False);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.swapBuffers(dpy, drawable);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXUseXFont(Font font, int first, int count, int list_base)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetCurrentDynDispatch();
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.useXFont(font, first, count, list_base);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXWaitGL(void)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetCurrentDynDispatch();
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.waitGL();
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXWaitX(void)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetCurrentDynDispatch();
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.waitX();
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
/**
|
|
|
|
* Queries a client string for each screen in a display.
|
|
|
|
*
|
|
|
|
* The returned array will have one element for each screen. The caller must
|
|
|
|
* free the array by calling free.
|
|
|
|
*
|
|
|
|
* \param dpy The display connection.
|
|
|
|
* \param name The string to query (GLX_VENDOR, GLX_VERSION, or GLX_EXTENSION).
|
|
|
|
* \return An array of strings, or NULL on error.
|
|
|
|
*/
|
|
|
|
static const char **GetVendorClientStrings(Display *dpy, int name)
|
|
|
|
{
|
|
|
|
int num_screens = XScreenCount(dpy);
|
|
|
|
const char **result = malloc(num_screens * sizeof(const char *));
|
|
|
|
int screen;
|
|
|
|
if (result == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (screen = 0; screen < num_screens; screen++) {
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, screen);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
result[screen] = vendor->staticDispatch.getClientString(dpy, name);
|
|
|
|
} else {
|
|
|
|
result[screen] = NULL;
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
if (result[screen] == NULL) {
|
|
|
|
free(result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-10-13 21:22:13 +02:00
|
|
|
/*!
|
|
|
|
* Parses the version string that you'd get from calling glXGetClientString
|
|
|
|
* with GLX_VERSION.
|
2015-04-13 21:38:35 +02:00
|
|
|
*
|
2016-10-13 21:22:13 +02:00
|
|
|
* \param version The version string.
|
|
|
|
* \param[out] major The major version number.
|
|
|
|
* \param[out] minor The minor version number.
|
|
|
|
* \param[out] vendor Returns a pointer to the vendor-specific part of the
|
|
|
|
* string, or \c NULL if it there isn't any vendor-specific string.
|
|
|
|
* \return Zero on success, or -1 if \c version doesn't match the correct
|
|
|
|
* format.
|
2015-04-13 21:38:35 +02:00
|
|
|
*/
|
2016-10-13 21:22:13 +02:00
|
|
|
static int ParseClientVersionString(const char *version,
|
|
|
|
int *major, int *minor, const char **vendor)
|
2015-04-13 21:38:35 +02:00
|
|
|
{
|
2016-10-13 21:22:13 +02:00
|
|
|
int count;
|
|
|
|
const char *ptr;
|
2015-04-13 21:38:35 +02:00
|
|
|
|
2016-10-13 21:22:13 +02:00
|
|
|
count = sscanf(version, "%d.%d", major, minor);
|
|
|
|
if (count != 2) {
|
|
|
|
return -1;
|
2015-04-13 21:38:35 +02:00
|
|
|
}
|
|
|
|
|
2016-10-13 21:22:13 +02:00
|
|
|
// The vendor-specific info should be after the first space character.
|
|
|
|
*vendor = NULL;
|
|
|
|
ptr = strchr(version, ' ');
|
|
|
|
if (ptr != NULL) {
|
|
|
|
while (*ptr == ' ') {
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
if (*ptr != '\0') {
|
|
|
|
*vendor = ptr;
|
2015-04-13 21:38:35 +02:00
|
|
|
}
|
|
|
|
}
|
2016-10-13 21:22:13 +02:00
|
|
|
return 0;
|
2015-04-13 21:38:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merges two GLX_VERSION strings.
|
|
|
|
*
|
|
|
|
* The merged string will specify the higher version number of \p currentString
|
|
|
|
* and \p newString, up to the version specified by \c GLX_MAJOR_VERSION and
|
|
|
|
* \c GLX_MINOR_VERSION.
|
|
|
|
*
|
|
|
|
* \param currentString The current string, which must have been allocated with malloc.
|
|
|
|
* \param newString The version string to merge.
|
|
|
|
* \return A new version string.
|
|
|
|
*/
|
|
|
|
static char *MergeVersionStrings(char *currentString, const char *newString)
|
|
|
|
{
|
|
|
|
int major, minor;
|
|
|
|
const char *vendorInfo;
|
|
|
|
int newMajor, newMinor;
|
|
|
|
const char *newVendorInfo;
|
|
|
|
char *buf;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ParseClientVersionString(currentString, &major, &minor, &vendorInfo) != 0) {
|
|
|
|
return currentString;
|
|
|
|
}
|
|
|
|
if (ParseClientVersionString(newString, &newMajor, &newMinor, &newVendorInfo) != 0) {
|
|
|
|
return currentString;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report the highest version number of any vendor library, but no higher
|
|
|
|
// than what this version of libglvnd supports.
|
|
|
|
if (newMajor > major || (newMajor == major && newMinor > minor)) {
|
|
|
|
major = newMajor;
|
|
|
|
minor = newMinor;
|
|
|
|
}
|
|
|
|
if (major > GLX_MAJOR_VERSION || (major == GLX_MAJOR_VERSION && minor > GLX_MINOR_VERSION)) {
|
|
|
|
major = GLX_MAJOR_VERSION;
|
|
|
|
minor = GLX_MINOR_VERSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vendorInfo != NULL && newVendorInfo != NULL) {
|
|
|
|
ret = glvnd_asprintf(&buf, "%d.%d %s, %s", major, minor, vendorInfo, newVendorInfo);
|
|
|
|
} else if (vendorInfo != NULL || newVendorInfo != NULL) {
|
|
|
|
const char *info = (vendorInfo != NULL ? vendorInfo : newVendorInfo);
|
|
|
|
ret = glvnd_asprintf(&buf, "%d.%d %s", major, minor, info);
|
|
|
|
} else {
|
|
|
|
ret = glvnd_asprintf(&buf, "%d.%d", major, minor);
|
|
|
|
}
|
|
|
|
free(currentString);
|
|
|
|
|
2015-11-20 20:48:25 +01:00
|
|
|
if (ret >= 0) {
|
2015-04-13 21:38:35 +02:00
|
|
|
return buf;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2016-01-08 21:25:46 +01:00
|
|
|
static const char *GetClientStringNoVendor(int name)
|
|
|
|
{
|
|
|
|
switch (name) {
|
|
|
|
case GLX_VENDOR:
|
|
|
|
return "libglvnd (no display specified)";
|
|
|
|
case GLX_VERSION:
|
|
|
|
return GLX_VERSION_STRING " (no display specified)";
|
|
|
|
case GLX_EXTENSIONS:
|
|
|
|
return "";
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC const char *glXGetClientString(Display *dpy, int name)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = NULL;
|
2016-01-08 21:25:46 +01:00
|
|
|
int num_screens;
|
2013-08-12 22:12:09 +02:00
|
|
|
int screen;
|
|
|
|
int index = name - 1;
|
2015-04-13 21:38:35 +02:00
|
|
|
const char **vendorStrings = NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-01-08 21:25:46 +01:00
|
|
|
if (dpy == NULL) {
|
|
|
|
return GetClientStringNoVendor(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
num_screens = XScreenCount(dpy);
|
|
|
|
|
2015-04-13 18:34:39 +02:00
|
|
|
if (num_screens == 1) {
|
|
|
|
// There's only one screen, so we don't have to mess around with
|
|
|
|
// merging the strings from multiple vendors.
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, 0);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.getClientString(dpy, name);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-04-13 18:34:39 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
if (name != GLX_VENDOR && name != GLX_VERSION && name != GLX_EXTENSIONS) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&clientStringLock);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
if (dpyInfo->clientStrings[index] != NULL) {
|
2015-04-13 21:38:35 +02:00
|
|
|
goto done;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
vendorStrings = GetVendorClientStrings(dpy, name);
|
|
|
|
if (vendorStrings == NULL) {
|
|
|
|
goto done;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
dpyInfo->clientStrings[index] = strdup(vendorStrings[0]);
|
|
|
|
if (dpyInfo->clientStrings[index] == NULL) {
|
2015-04-13 21:38:35 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
for (screen = 1; screen < num_screens; screen++) {
|
|
|
|
if (name == GLX_VENDOR) {
|
|
|
|
char *newBuf;
|
2015-04-14 19:58:43 +02:00
|
|
|
if (glvnd_asprintf(&newBuf, "%s, %s", dpyInfo->clientStrings[index], vendorStrings[screen]) < 0) {
|
2015-04-13 21:38:35 +02:00
|
|
|
newBuf = NULL;
|
|
|
|
}
|
2015-04-14 19:58:43 +02:00
|
|
|
free(dpyInfo->clientStrings[index]);
|
|
|
|
dpyInfo->clientStrings[index] = newBuf;
|
2015-04-13 21:38:35 +02:00
|
|
|
} else if (name == GLX_VERSION) {
|
2015-04-14 19:58:43 +02:00
|
|
|
dpyInfo->clientStrings[index] = MergeVersionStrings(dpyInfo->clientStrings[index], vendorStrings[screen]);
|
2015-04-13 21:38:35 +02:00
|
|
|
} else if (name == GLX_EXTENSIONS) {
|
2016-10-13 21:22:13 +02:00
|
|
|
dpyInfo->clientStrings[index] = UnionExtensionStrings(dpyInfo->clientStrings[index], vendorStrings[screen]);
|
2015-04-13 21:38:35 +02:00
|
|
|
} else {
|
|
|
|
assert(!"Can't happen: Invalid string name");
|
2015-04-14 19:58:43 +02:00
|
|
|
free(dpyInfo->clientStrings[index]);
|
|
|
|
dpyInfo->clientStrings[index] = NULL;
|
2015-04-13 21:38:35 +02:00
|
|
|
}
|
2015-04-14 19:58:43 +02:00
|
|
|
if (dpyInfo->clientStrings[index] == NULL) {
|
2015-04-13 21:38:35 +02:00
|
|
|
goto done;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:38:35 +02:00
|
|
|
done:
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&clientStringLock);
|
2015-04-13 21:38:35 +02:00
|
|
|
if (vendorStrings != NULL) {
|
|
|
|
free(vendorStrings);
|
|
|
|
}
|
2015-04-14 19:58:43 +02:00
|
|
|
return dpyInfo->clientStrings[index];
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC const char *glXQueryServerString(Display *dpy, int screen, int name)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, screen);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.queryServerString(dpy, screen, name);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC const char *glXQueryExtensionsString(Display *dpy, int screen)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, screen);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.queryExtensionsString(dpy, screen);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen,
|
|
|
|
const int *attrib_list, int *nelements)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, screen);
|
2016-01-04 21:20:46 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
GLXFBConfig *fbconfigs =
|
|
|
|
vendor->staticDispatch.chooseFBConfig(dpy, screen, attrib_list, nelements);
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2016-01-04 21:20:46 +01:00
|
|
|
if (fbconfigs != NULL) {
|
|
|
|
int i;
|
2016-02-26 22:05:38 +01:00
|
|
|
Bool success = True;
|
2016-01-04 21:20:46 +01:00
|
|
|
for (i = 0; i < *nelements; i++) {
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor) != 0) {
|
|
|
|
success = False;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!success) {
|
|
|
|
XFree(fbconfigs);
|
|
|
|
fbconfigs = NULL;
|
|
|
|
*nelements = 0;
|
2016-01-04 21:20:46 +01:00
|
|
|
}
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
2016-01-04 21:20:46 +01:00
|
|
|
return fbconfigs;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config,
|
2013-08-23 01:06:53 +02:00
|
|
|
const int *attrib_list)
|
|
|
|
{
|
2015-12-18 21:25:47 +01:00
|
|
|
GLXPbuffer pbuffer = None;
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreatePbuffer);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
pbuffer = vendor->staticDispatch.createPbuffer(dpy, config, attrib_list);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorDrawableMapping(dpy, pbuffer, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyPbuffer(dpy, pbuffer);
|
|
|
|
pbuffer = None;
|
|
|
|
}
|
2015-12-18 21:25:47 +01:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
return pbuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config,
|
2013-08-23 01:06:53 +02:00
|
|
|
Pixmap pixmap, const int *attrib_list)
|
|
|
|
{
|
2015-12-18 21:25:47 +01:00
|
|
|
GLXPixmap glxPixmap = None;
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreatePixmap);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
glxPixmap = vendor->staticDispatch.createPixmap(dpy, config, pixmap, attrib_list);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorDrawableMapping(dpy, glxPixmap, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyGLXPixmap(dpy, glxPixmap);
|
|
|
|
glxPixmap = None;
|
|
|
|
}
|
2015-12-18 21:25:47 +01:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
return glxPixmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config,
|
2013-08-23 01:06:53 +02:00
|
|
|
Window win, const int *attrib_list)
|
|
|
|
{
|
2015-12-18 21:25:47 +01:00
|
|
|
GLXWindow glxWindow = None;
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreateWindow);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
glxWindow = vendor->staticDispatch.createWindow(dpy, config, win, attrib_list);
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorDrawableMapping(dpy, glxWindow, vendor) != 0) {
|
|
|
|
vendor->staticDispatch.destroyWindow(dpy, glxWindow);
|
|
|
|
glxWindow = None;
|
|
|
|
}
|
2015-12-18 21:25:47 +01:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
return glxWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, pbuf,
|
|
|
|
X_GLXDestroyPbuffer, GLXBadPbuffer, False);
|
|
|
|
if (vendor != NULL) {
|
2016-01-04 20:37:08 +01:00
|
|
|
__glXRemoveVendorDrawableMapping(dpy, pbuf);
|
2015-12-18 18:48:14 +01:00
|
|
|
vendor->staticDispatch.destroyPbuffer(dpy, pbuf);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, pixmap,
|
|
|
|
X_GLXDestroyPixmap, GLXBadPixmap, False);
|
|
|
|
if (vendor != NULL) {
|
2016-01-04 20:37:08 +01:00
|
|
|
__glXRemoveVendorDrawableMapping(dpy, pixmap);
|
2015-12-18 18:48:14 +01:00
|
|
|
vendor->staticDispatch.destroyPixmap(dpy, pixmap);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXDestroyWindow(Display *dpy, GLXWindow win)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, win,
|
|
|
|
X_GLXDestroyWindow, GLXBadWindow, False);
|
|
|
|
if (vendor != NULL) {
|
2016-01-04 20:37:08 +01:00
|
|
|
__glXRemoveVendorDrawableMapping(dpy, win);
|
2015-12-18 18:48:14 +01:00
|
|
|
vendor->staticDispatch.destroyWindow(dpy, win);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config,
|
2013-08-23 01:06:53 +02:00
|
|
|
int attribute, int *value)
|
|
|
|
{
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXGetFBConfigs);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.getFBConfigAttrib(dpy, config, attribute, value);
|
|
|
|
} else {
|
|
|
|
return GLX_BAD_VISUAL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-05-04 18:36:11 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXGetDynDispatch(dpy, screen);
|
2016-01-04 21:20:46 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
GLXFBConfig *fbconfigs = vendor->staticDispatch.getFBConfigs(dpy, screen, nelements);
|
|
|
|
if (fbconfigs != NULL) {
|
|
|
|
int i;
|
2016-03-14 20:55:16 +01:00
|
|
|
Bool success = True;
|
2016-01-04 21:20:46 +01:00
|
|
|
for (i = 0; i < *nelements; i++) {
|
2016-02-26 22:05:38 +01:00
|
|
|
if (__glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor) != 0) {
|
|
|
|
success = False;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!success) {
|
|
|
|
XFree(fbconfigs);
|
|
|
|
fbconfigs = NULL;
|
|
|
|
*nelements = 0;
|
2016-01-04 21:20:46 +01:00
|
|
|
}
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
2016-01-04 21:20:46 +01:00
|
|
|
return fbconfigs;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXGetSelectedEvent(Display *dpy, GLXDrawable draw,
|
2013-08-23 01:06:53 +02:00
|
|
|
unsigned long *event_mask)
|
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
// glXGetSelectedEvent uses the glXGetDrawableAttributes protocol.
|
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, draw,
|
|
|
|
X_GLXGetDrawableAttributes, GLXBadDrawable, False);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.getSelectedEvent(dpy, draw, event_mask);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-01-04 21:20:46 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXGetFBConfigs);
|
2015-12-18 21:25:47 +01:00
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.getVisualFromFBConfig(dpy, config);
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC int glXQueryContext(Display *dpy, GLXContext context, int attribute, int *value)
|
|
|
|
{
|
2015-12-18 19:10:35 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchContext(dpy, context, X_GLXQueryContext);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor->staticDispatch.queryContext(dpy, context, attribute, value);
|
|
|
|
} else {
|
|
|
|
return GLX_BAD_CONTEXT;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXQueryDrawable(Display *dpy, GLXDrawable draw,
|
|
|
|
int attribute, unsigned int *value)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, draw,
|
|
|
|
X_GLXGetDrawableAttributes, GLXBadDrawable, False);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.queryDrawable(dpy, draw, attribute, value);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC void glXSelectEvent(Display *dpy, GLXDrawable draw, unsigned long event_mask)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-18 18:48:14 +01:00
|
|
|
__GLXvendorInfo *vendor = CommonDispatchDrawable(dpy, draw,
|
|
|
|
X_GLXChangeDrawableAttributes, GLXBadDrawable, False);
|
|
|
|
if (vendor != NULL) {
|
|
|
|
vendor->staticDispatch.selectEvent(dpy, draw, event_mask);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-05-03 22:12:05 +02:00
|
|
|
const __GLXlocalDispatchFunction LOCAL_GLX_DISPATCH_FUNCTIONS[] =
|
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
#define LOCAL_FUNC_TABLE_ENTRY(func) \
|
2016-05-03 22:12:05 +02:00
|
|
|
{ #func, (__GLXextFuncPtr)(func) },
|
2013-08-12 22:12:09 +02:00
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXChooseFBConfig)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXChooseVisual)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCopyContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreateContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreateGLXPixmap)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreateNewContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreatePbuffer)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreatePixmap)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreateWindow)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXDestroyContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXDestroyGLXPixmap)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXDestroyPbuffer)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXDestroyPixmap)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXDestroyWindow)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetClientString)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetConfig)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetCurrentContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetCurrentDisplay)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetCurrentDrawable)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetCurrentReadDrawable)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetFBConfigAttrib)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetFBConfigs)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetProcAddress)
|
2013-11-07 00:37:19 +01:00
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetProcAddressARB)
|
2013-08-12 22:12:09 +02:00
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetSelectedEvent)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXGetVisualFromFBConfig)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXIsDirect)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXMakeContextCurrent)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXMakeCurrent)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryContext)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryDrawable)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryExtension)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryExtensionsString)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryServerString)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXQueryVersion)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXSelectEvent)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXSwapBuffers)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXUseXFont)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXWaitGL)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXWaitX)
|
2015-10-15 00:57:17 +02:00
|
|
|
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXImportContextEXT)
|
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXFreeContextEXT)
|
2017-11-29 22:38:50 +01:00
|
|
|
LOCAL_FUNC_TABLE_ENTRY(glXCreateContextAttribsARB)
|
2016-05-03 22:12:05 +02:00
|
|
|
#undef LOCAL_FUNC_TABLE_ENTRY
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-05-03 22:12:05 +02:00
|
|
|
typedef struct {
|
|
|
|
GLubyte *procName;
|
|
|
|
__GLXextFuncPtr addr;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXprocAddressHash;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-05-03 22:12:05 +02:00
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXprocAddressHash, __glXProcAddressHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
Re-implement libGL such that ELF symbol filtering is optional
Unfortunately, glibc has a bug where dlopening a shared library with
DT_FILTER or DT_AUXILIARY ELF headers can cause the application to
segfault (see https://sourceware.org/bugzilla/show_bug.cgi?id=16272).
Hence, for now, we can't rely on ELF symbol filtering to implement the
libGL compatibility library for libGLdispatch and libGLX. This change
re-implements libGL such that this is no longer necessary, by building
in the glapi static dispatch stubs and implementing thin wrapper
functions around GLX entrypoints.
- Rename getCachedProcAddress() to __glXGetCachedProcAddress() and give
this public visibility. This is used by the libGL wrapper library to
retrieve GLX entrypoints at load time.
- Link libGLX with the -Bsymbolic flag so __glXGetCachedProcAddress()
avoids referencing functions in the libGL wrapper library when libGL
and libGLX are both loaded.
- Replace the hand-coded no-op definitions in libglxnoopdefs.h with
a spec file, glx_funcs.spec, and a simple Perl script, gen_stubs.pl,
which parses the file and generates no-op functions as well as
pass-through functions that are used by libGL.
- Restructure GLdispatch/vnd-glapi/mapi/entry.c such that the pure C
fallback code is in its own header, entry_pure_c.h. In each of the
entry_*.h headers, separate code not related to implementing the
static dispatch stubs into an "#if !defined(STATIC_DISPATCH_ONLY)"
block.
- Give u_current (which is #defined as _glapi_Current or
_glapi_tls_Current depending on the thread storage model used) public
visibility so it can be referenced from outside of libGLdispatch.so.
- When building libGL, include GLdispatch/vnd-glapi/mapi/entry.c in the
sources, and define STATIC_DISPATCH_ONLY so that only the static
entrypoints are compiled. Remove the -Wl,--auxiliary flags from
Makefile.am.
Bonus: fix "make distcheck" by adding GLdispatchABI.h to noinst_HEADERS.
Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
2013-12-03 21:06:47 +01:00
|
|
|
/*
|
|
|
|
* This function is called externally by the libGL wrapper library to
|
|
|
|
* retrieve libGLX entrypoints.
|
|
|
|
*/
|
2015-10-29 19:32:22 +01:00
|
|
|
static __GLXextFuncPtr __glXGetCachedProcAddress(const GLubyte *procName)
|
2013-08-23 01:14:33 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If this is the first time GetProcAddress has been called,
|
2013-08-12 22:12:09 +02:00
|
|
|
* initialize the hash table with locally-exported functions.
|
2013-08-23 01:14:33 +02:00
|
|
|
*/
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXprocAddressHash *pEntry = NULL;
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(__glXProcAddressHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
HASH_FIND(hh, _LH(__glXProcAddressHash), procName,
|
2013-08-12 22:12:09 +02:00
|
|
|
strlen((const char *)procName), pEntry);
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXProcAddressHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry) {
|
|
|
|
return pEntry->addr;
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cacheProcAddress(const GLubyte *procName, __GLXextFuncPtr addr)
|
|
|
|
{
|
2016-05-03 22:27:22 +02:00
|
|
|
size_t nameLen = strlen((const char *) procName);
|
|
|
|
__GLXprocAddressHash *pEntry;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-05-03 22:27:22 +02:00
|
|
|
LKDHASH_WRLOCK(__glXProcAddressHash);
|
2013-09-04 07:39:08 +02:00
|
|
|
|
2016-05-03 22:27:22 +02:00
|
|
|
HASH_FIND(hh, _LH(__glXProcAddressHash), procName,
|
|
|
|
nameLen, pEntry);
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry) + nameLen + 1);
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
pEntry->procName = (GLubyte *) (pEntry + 1);
|
|
|
|
memcpy(pEntry->procName, procName, nameLen + 1);
|
|
|
|
pEntry->addr = addr;
|
|
|
|
HASH_ADD_KEYPTR(hh, _LH(__glXProcAddressHash), pEntry->procName,
|
|
|
|
nameLen, pEntry);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(pEntry->addr == addr);
|
2013-09-04 07:39:08 +02:00
|
|
|
}
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXProcAddressHash);
|
2013-08-23 01:14:33 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-11-07 00:37:19 +01:00
|
|
|
PUBLIC __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *procName)
|
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2013-11-07 00:37:19 +01:00
|
|
|
return glXGetProcAddress(procName);
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
PUBLIC __GLXextFuncPtr glXGetProcAddress(const GLubyte *procName)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-23 01:14:33 +02:00
|
|
|
__GLXextFuncPtr addr = NULL;
|
|
|
|
|
2016-05-03 20:31:27 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
/*
|
|
|
|
* Easy case: First check if we already know this address from
|
|
|
|
* a previous GetProcAddress() call or by virtue of being a function
|
|
|
|
* exported by libGLX.
|
|
|
|
*/
|
Re-implement libGL such that ELF symbol filtering is optional
Unfortunately, glibc has a bug where dlopening a shared library with
DT_FILTER or DT_AUXILIARY ELF headers can cause the application to
segfault (see https://sourceware.org/bugzilla/show_bug.cgi?id=16272).
Hence, for now, we can't rely on ELF symbol filtering to implement the
libGL compatibility library for libGLdispatch and libGLX. This change
re-implements libGL such that this is no longer necessary, by building
in the glapi static dispatch stubs and implementing thin wrapper
functions around GLX entrypoints.
- Rename getCachedProcAddress() to __glXGetCachedProcAddress() and give
this public visibility. This is used by the libGL wrapper library to
retrieve GLX entrypoints at load time.
- Link libGLX with the -Bsymbolic flag so __glXGetCachedProcAddress()
avoids referencing functions in the libGL wrapper library when libGL
and libGLX are both loaded.
- Replace the hand-coded no-op definitions in libglxnoopdefs.h with
a spec file, glx_funcs.spec, and a simple Perl script, gen_stubs.pl,
which parses the file and generates no-op functions as well as
pass-through functions that are used by libGL.
- Restructure GLdispatch/vnd-glapi/mapi/entry.c such that the pure C
fallback code is in its own header, entry_pure_c.h. In each of the
entry_*.h headers, separate code not related to implementing the
static dispatch stubs into an "#if !defined(STATIC_DISPATCH_ONLY)"
block.
- Give u_current (which is #defined as _glapi_Current or
_glapi_tls_Current depending on the thread storage model used) public
visibility so it can be referenced from outside of libGLdispatch.so.
- When building libGL, include GLdispatch/vnd-glapi/mapi/entry.c in the
sources, and define STATIC_DISPATCH_ONLY so that only the static
entrypoints are compiled. Remove the -Wl,--auxiliary flags from
Makefile.am.
Bonus: fix "make distcheck" by adding GLdispatchABI.h to noinst_HEADERS.
Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
2013-12-03 21:06:47 +01:00
|
|
|
addr = __glXGetCachedProcAddress(procName);
|
2013-08-23 01:14:33 +02:00
|
|
|
if (addr) {
|
|
|
|
return addr;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2016-05-03 20:31:27 +02:00
|
|
|
if (procName[0] == 'g' && procName[1] == 'l' && procName[2] == 'X') {
|
|
|
|
// This looks like a GLX function, so try to find a GLX dispatch stub.
|
|
|
|
addr = __glXGetGLXDispatchAddress(procName);
|
|
|
|
} else {
|
|
|
|
addr = __glDispatchGetProcAddress((const char *) procName);
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
2013-08-23 01:14:33 +02:00
|
|
|
|
|
|
|
/* Store the resulting proc address. */
|
|
|
|
if (addr) {
|
|
|
|
cacheProcAddress(procName, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-05-03 22:27:22 +02:00
|
|
|
PUBLIC __GLXextFuncPtr __glXGLLoadGLXFunction(const char *name,
|
|
|
|
__GLXextFuncPtr *ptr, glvnd_mutex_t *mutex)
|
|
|
|
{
|
|
|
|
__GLXextFuncPtr func;
|
|
|
|
|
2017-06-20 20:53:54 +02:00
|
|
|
__glvndPthreadFuncs.mutex_lock(mutex);
|
2016-05-03 22:27:22 +02:00
|
|
|
|
|
|
|
func = *ptr;
|
|
|
|
if (func == NULL) {
|
|
|
|
func = glXGetProcAddress((const GLubyte *) name);
|
|
|
|
*ptr = func;
|
|
|
|
}
|
|
|
|
|
2017-06-20 20:53:54 +02:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(mutex);
|
2016-05-03 22:27:22 +02:00
|
|
|
return func;
|
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
int AtomicIncrement(int volatile *val)
|
|
|
|
{
|
2015-03-27 18:38:58 +01:00
|
|
|
#if defined(HAVE_SYNC_INTRINSICS)
|
2014-10-03 01:17:59 +02:00
|
|
|
return __sync_add_and_fetch(val, 1);
|
2015-03-31 01:00:14 +02:00
|
|
|
#elif defined(USE_X86_ASM) || defined(USE_X86_64_ASM)
|
2015-03-27 18:38:58 +01:00
|
|
|
int result;
|
|
|
|
int delta = 1;
|
|
|
|
|
|
|
|
__asm __volatile__ ("lock; xaddl %0, %1"
|
|
|
|
: "=r" (result), "=m" (*val)
|
|
|
|
: "0" (delta), "m" (*val));
|
|
|
|
|
|
|
|
return result + delta;
|
2015-03-31 01:00:14 +02:00
|
|
|
#else
|
|
|
|
#error "Not implemented"
|
2015-03-27 18:38:58 +01:00
|
|
|
#endif
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int AtomicSwap(int volatile *val, int newVal)
|
|
|
|
{
|
2015-03-27 18:38:58 +01:00
|
|
|
#if defined(HAVE_SYNC_INTRINSICS)
|
2014-10-03 01:17:59 +02:00
|
|
|
return __sync_lock_test_and_set(val, newVal);
|
2015-03-31 01:00:14 +02:00
|
|
|
#elif defined(USE_X86_ASM) || defined(USE_X86_64_ASM)
|
2015-03-27 18:38:58 +01:00
|
|
|
int result;
|
|
|
|
|
|
|
|
__asm __volatile__ ("xchgl %0, %1"
|
|
|
|
: "=r" (result), "=m" (*val)
|
|
|
|
: "0" (newVal), "m" (*val));
|
|
|
|
|
|
|
|
return result;
|
2015-03-31 01:00:14 +02:00
|
|
|
#else
|
|
|
|
#error "Not implemented"
|
2015-03-27 18:38:58 +01:00
|
|
|
#endif
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int AtomicCompareAndSwap(int volatile *val, int oldVal, int newVal)
|
|
|
|
{
|
2015-03-27 18:38:58 +01:00
|
|
|
#if defined(HAVE_SYNC_INTRINSICS)
|
2014-10-03 01:17:59 +02:00
|
|
|
return __sync_val_compare_and_swap(val, oldVal, newVal);
|
2015-03-31 01:00:14 +02:00
|
|
|
#elif defined(USE_X86_ASM) || defined(USE_X86_64_ASM)
|
2015-03-27 18:38:58 +01:00
|
|
|
int result;
|
|
|
|
|
|
|
|
__asm __volatile__ ("lock; cmpxchgl %2, %1"
|
|
|
|
: "=a" (result), "=m" (*val)
|
|
|
|
: "r" (newVal), "m" (*val), "0" (oldVal));
|
|
|
|
|
|
|
|
return result;
|
2015-03-31 01:00:14 +02:00
|
|
|
#else
|
|
|
|
#error "Not implemented"
|
2015-03-27 18:38:58 +01:00
|
|
|
#endif
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int AtomicDecrementClampAtZero(int volatile *val)
|
|
|
|
{
|
|
|
|
int oldVal, newVal;
|
|
|
|
|
|
|
|
oldVal = *val;
|
|
|
|
newVal = oldVal;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (oldVal <= 0) {
|
|
|
|
assert(oldVal == 0);
|
|
|
|
} else {
|
|
|
|
newVal = oldVal - 1;
|
|
|
|
oldVal = AtomicCompareAndSwap(val, oldVal, newVal);
|
|
|
|
}
|
|
|
|
} while ((oldVal > 0) && (newVal != oldVal - 1));
|
|
|
|
|
|
|
|
return newVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __glXResetOnFork(void);
|
|
|
|
|
2016-04-01 17:18:33 +02:00
|
|
|
/*!
|
|
|
|
* Checks to see if a fork occurred since the last GLX entrypoint was called,
|
|
|
|
* and performs recovery if needed.
|
2014-10-03 01:17:59 +02:00
|
|
|
*/
|
2016-04-01 17:18:33 +02:00
|
|
|
static void CheckFork(void)
|
2014-10-03 01:17:59 +02:00
|
|
|
{
|
|
|
|
volatile static int g_threadsInCheck = 0;
|
|
|
|
volatile static int g_lastPid = -1;
|
|
|
|
|
|
|
|
int lastPid;
|
|
|
|
int pid = getpid();
|
|
|
|
|
|
|
|
AtomicIncrement(&g_threadsInCheck);
|
|
|
|
|
|
|
|
lastPid = AtomicSwap(&g_lastPid, pid);
|
|
|
|
|
|
|
|
if ((lastPid != -1) &&
|
|
|
|
(lastPid != pid)) {
|
|
|
|
|
|
|
|
DBG_PRINTF(0, "Fork detected\n");
|
|
|
|
|
|
|
|
__glXResetOnFork();
|
|
|
|
|
|
|
|
// Force g_threadsInCheck to 0 to unblock other threads waiting here.
|
|
|
|
g_threadsInCheck = 0;
|
|
|
|
} else {
|
|
|
|
AtomicDecrementClampAtZero(&g_threadsInCheck);
|
|
|
|
while (g_threadsInCheck > 0) {
|
|
|
|
// Wait for other threads to finish checking for a fork.
|
|
|
|
//
|
|
|
|
// If a fork happens while g_threadsInCheck > 0 the _first_ thread
|
|
|
|
// to enter __glXThreadInitialize() will see the fork, handle it, and force
|
|
|
|
// g_threadsInCheck to 0, unblocking any other threads stuck here.
|
|
|
|
sched_yield();
|
|
|
|
}
|
|
|
|
}
|
2016-04-01 17:18:33 +02:00
|
|
|
}
|
2015-04-02 00:55:39 +02:00
|
|
|
|
2016-04-01 17:18:33 +02:00
|
|
|
/*!
|
|
|
|
* Handles any common tasks that need to occur at the beginning of any GLX
|
|
|
|
* entrypoint.
|
|
|
|
*/
|
|
|
|
void __glXThreadInitialize(void)
|
|
|
|
{
|
|
|
|
CheckFork();
|
2015-04-02 00:55:39 +02:00
|
|
|
__glDispatchCheckMultithreaded();
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __glXAPITeardown(Bool doReset)
|
|
|
|
{
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLXThreadState *threadState, *threadStateTemp;
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXcontextInfo *currContext, *currContextTemp;
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
glvnd_list_for_each_entry_safe(threadState, threadStateTemp, ¤tThreadStateList, entry) {
|
|
|
|
glvnd_list_del(&threadState->entry);
|
|
|
|
free(threadState);
|
2015-10-08 02:56:02 +02:00
|
|
|
}
|
2014-10-03 01:17:59 +02:00
|
|
|
|
|
|
|
if (doReset) {
|
|
|
|
/*
|
|
|
|
* XXX: We should be able to get away with just resetting the proc address
|
|
|
|
* hash lock, and not throwing away cached addresses.
|
|
|
|
*/
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_init(&__glXProcAddressHash.lock, NULL);
|
2016-03-04 21:01:34 +01:00
|
|
|
__glvndPthreadFuncs.mutex_init(¤tThreadStateListMutex, NULL);
|
2016-07-13 18:09:17 +02:00
|
|
|
|
|
|
|
HASH_ITER(hh, glxContextHash, currContext, currContextTemp) {
|
|
|
|
currContext->currentCount = 0;
|
|
|
|
CheckContextDeleted(currContext);
|
|
|
|
}
|
2014-10-03 01:17:59 +02:00
|
|
|
} else {
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXprocAddressHash,
|
2016-05-03 22:27:22 +02:00
|
|
|
__glXProcAddressHash, NULL, NULL, False);
|
2016-07-13 18:09:17 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It's possible that another thread could be blocked in a
|
|
|
|
* glXMakeCurrent call here, especially if an Xlib I/O error occurred.
|
|
|
|
* In that case, the other thead will be holding the context hash lock,
|
|
|
|
* so we'd deadlock if we tried to wait for it here. Instead, clean up
|
|
|
|
* if the lock is available, but don't try to wait if it isn't.
|
|
|
|
*/
|
|
|
|
if (__glvndPthreadFuncs.mutex_trylock(&glxContextHashLock) == 0) {
|
|
|
|
HASH_ITER(hh, glxContextHash, currContext, currContextTemp) {
|
|
|
|
FreeContextInfo(currContext);
|
|
|
|
}
|
|
|
|
assert(glxContextHash == NULL);
|
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxContextHashLock);
|
|
|
|
}
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __glXResetOnFork(void)
|
|
|
|
{
|
2015-10-08 02:56:02 +02:00
|
|
|
/* Reset GLdispatch */
|
|
|
|
__glDispatchReset();
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/* Reset all GLX API state */
|
|
|
|
__glXAPITeardown(True);
|
|
|
|
|
|
|
|
/* Reset all mapping state */
|
|
|
|
__glXMappingTeardown(True);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2017-06-20 20:53:54 +02:00
|
|
|
PUBLIC const __glXGLCoreFunctions __GLXGL_CORE_FUNCTIONS = {
|
|
|
|
glXChooseFBConfig,
|
|
|
|
glXChooseVisual,
|
|
|
|
glXCopyContext,
|
|
|
|
glXCreateContext,
|
|
|
|
glXCreateGLXPixmap,
|
|
|
|
glXCreateNewContext,
|
|
|
|
glXCreatePbuffer,
|
|
|
|
glXCreatePixmap,
|
|
|
|
glXCreateWindow,
|
|
|
|
glXDestroyContext,
|
|
|
|
glXDestroyGLXPixmap,
|
|
|
|
glXDestroyPbuffer,
|
|
|
|
glXDestroyPixmap,
|
|
|
|
glXDestroyWindow,
|
|
|
|
glXGetClientString,
|
|
|
|
glXGetConfig,
|
|
|
|
glXGetCurrentContext,
|
|
|
|
glXGetCurrentDrawable,
|
|
|
|
glXGetCurrentReadDrawable,
|
|
|
|
glXGetFBConfigAttrib,
|
|
|
|
glXGetFBConfigs,
|
|
|
|
glXGetProcAddress,
|
|
|
|
glXGetProcAddressARB,
|
|
|
|
glXGetSelectedEvent,
|
|
|
|
glXGetVisualFromFBConfig,
|
|
|
|
glXIsDirect,
|
|
|
|
glXMakeContextCurrent,
|
|
|
|
glXMakeCurrent,
|
|
|
|
glXQueryContext,
|
|
|
|
glXQueryDrawable,
|
|
|
|
glXQueryExtension,
|
|
|
|
glXQueryExtensionsString,
|
|
|
|
glXQueryServerString,
|
|
|
|
glXQueryVersion,
|
|
|
|
glXSelectEvent,
|
|
|
|
glXSwapBuffers,
|
|
|
|
glXUseXFont,
|
|
|
|
glXWaitGL,
|
|
|
|
glXWaitX,
|
|
|
|
};
|
|
|
|
|
2015-03-27 18:38:58 +01:00
|
|
|
#if defined(USE_ATTRIBUTE_CONSTRUCTOR)
|
2013-08-23 01:14:33 +02:00
|
|
|
void __attribute__ ((constructor)) __glXInit(void)
|
2015-03-27 18:38:58 +01:00
|
|
|
#else
|
|
|
|
void _init(void)
|
|
|
|
#endif
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-12-09 23:56:36 +01:00
|
|
|
glvnd_mutexattr_t mutexAttribs;
|
|
|
|
|
2015-07-06 20:08:54 +02:00
|
|
|
if (__glDispatchGetABIVersion() != GLDISPATCH_ABI_VERSION) {
|
|
|
|
fprintf(stderr, "libGLdispatch ABI version is incompatible with libGLX.\n");
|
|
|
|
abort();
|
|
|
|
}
|
2013-08-23 01:14:33 +02:00
|
|
|
|
2014-01-24 04:47:51 +01:00
|
|
|
/* Initialize GLdispatch; this will also initialize our pthreads imports */
|
2015-06-11 22:27:23 +02:00
|
|
|
__glDispatchInit();
|
2016-02-23 00:16:59 +01:00
|
|
|
glvndSetupPthreads();
|
2016-04-05 20:58:17 +02:00
|
|
|
glvndAppErrorCheckInit();
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-04 21:01:34 +01:00
|
|
|
glvnd_list_init(¤tThreadStateList);
|
2015-10-08 02:56:02 +02:00
|
|
|
|
2015-12-09 23:56:36 +01:00
|
|
|
/*
|
2016-02-10 00:50:37 +01:00
|
|
|
* glxContextHashLock must be a recursive mutex, because we'll have it
|
2015-12-09 23:56:36 +01:00
|
|
|
* locked when we call into the vendor library's glXMakeCurrent
|
|
|
|
* implementation. If the vendor library generates an X error, then that
|
|
|
|
* will often result in a call to exit. In that case, the teardown code
|
|
|
|
* will try to lock the mutex again so that it can clean up the current
|
|
|
|
* context list.
|
|
|
|
*/
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutexattr_init(&mutexAttribs);
|
|
|
|
__glvndPthreadFuncs.mutexattr_settype(&mutexAttribs, PTHREAD_MUTEX_RECURSIVE);
|
2016-02-10 00:50:37 +01:00
|
|
|
__glvndPthreadFuncs.mutex_init(&glxContextHashLock, &mutexAttribs);
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutexattr_destroy(&mutexAttribs);
|
2015-12-09 23:56:36 +01:00
|
|
|
|
2016-05-03 20:31:27 +02:00
|
|
|
__glXMappingInit();
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Check if we need to pre-load any vendors specified via environment
|
|
|
|
* variable.
|
|
|
|
*/
|
|
|
|
const char *preloadedVendor = getenv("__GLX_VENDOR_LIBRARY_NAME");
|
2013-08-23 01:16:15 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
if (preloadedVendor) {
|
|
|
|
__glXLookupVendorByName(preloadedVendor);
|
|
|
|
}
|
2013-08-23 01:16:15 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/* TODO install fork handlers using __register_atfork */
|
|
|
|
|
2013-08-23 01:20:01 +02:00
|
|
|
DBG_PRINTF(0, "Loading GLX...\n");
|
2013-08-23 01:16:15 +02:00
|
|
|
|
2013-08-23 01:14:33 +02:00
|
|
|
}
|
|
|
|
|
2015-03-27 18:38:58 +01:00
|
|
|
#if defined(USE_ATTRIBUTE_CONSTRUCTOR)
|
2013-08-23 01:14:33 +02:00
|
|
|
void __attribute__ ((destructor)) __glXFini(void)
|
2015-03-27 18:38:58 +01:00
|
|
|
#else
|
|
|
|
void _fini(void)
|
|
|
|
#endif
|
2013-08-23 01:14:33 +02:00
|
|
|
{
|
2016-04-01 17:18:33 +02:00
|
|
|
/*
|
|
|
|
* Note that the dynamic linker may have already called the destructors for
|
|
|
|
* the vendor libraries. As a result, we can't do anything here that would
|
|
|
|
* try to call into any vendor library.
|
|
|
|
*/
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/* Check for a fork before going further. */
|
2016-04-01 17:18:33 +02:00
|
|
|
CheckFork();
|
2014-10-03 01:17:59 +02:00
|
|
|
|
|
|
|
/*
|
2016-03-04 21:01:34 +01:00
|
|
|
* If libGLX owns the current thread state, lose current
|
2014-10-03 01:17:59 +02:00
|
|
|
* in GLdispatch before going further.
|
|
|
|
*/
|
2016-03-04 21:01:34 +01:00
|
|
|
__GLdispatchThreadState *glas =
|
|
|
|
__glDispatchGetCurrentThreadState();
|
2014-10-03 01:17:59 +02:00
|
|
|
|
|
|
|
if (glas && glas->tag == GLDISPATCH_API_GLX) {
|
|
|
|
__glDispatchLoseCurrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tear down all GLX API state */
|
|
|
|
__glXAPITeardown(False);
|
|
|
|
|
|
|
|
/* Tear down all mapping state */
|
|
|
|
__glXMappingTeardown(False);
|
|
|
|
|
|
|
|
/* Tear down GLdispatch if necessary */
|
|
|
|
__glDispatchFini();
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
2013-08-23 01:16:15 +02:00
|
|
|
|