0,0 → 1,656 |
/** |
* GLX initialization. Code based on glxext.c, glx_query.c, and |
* glcontextmodes.c under src/glx/. The major difference is that DRI |
* related code is stripped out. |
* |
* If the maintenance of this file takes too much time, we should consider |
* refactoring glxext.c. |
*/ |
|
#include <assert.h> |
#include <X11/Xlib.h> |
#include <X11/Xproto.h> |
#include <X11/Xlibint.h> |
#include <X11/extensions/Xext.h> |
#include <X11/extensions/extutil.h> |
#include <sys/time.h> |
|
#include "GL/glxproto.h" |
#include "GL/glxtokens.h" |
#include "GL/gl.h" /* for GL types needed by __GLcontextModes */ |
#include "glcore.h" /* for __GLcontextModes */ |
|
#include "glxinit.h" |
|
#ifdef GLX_DIRECT_RENDERING |
|
typedef struct GLXGenericGetString |
{ |
CARD8 reqType; |
CARD8 glxCode; |
CARD16 length B16; |
CARD32 for_whom B32; |
CARD32 name B32; |
} xGLXGenericGetStringReq; |
|
#define sz_xGLXGenericGetStringReq 12 |
#define X_GLXGenericGetString 0 |
|
/* Extension required boiler plate */ |
|
static char *__glXExtensionName = GLX_EXTENSION_NAME; |
static XExtensionInfo *__glXExtensionInfo = NULL; |
|
static int |
__glXCloseDisplay(Display * dpy, XExtCodes * codes) |
{ |
return XextRemoveDisplay(__glXExtensionInfo, dpy); |
} |
|
static /* const */ XExtensionHooks __glXExtensionHooks = { |
NULL, /* create_gc */ |
NULL, /* copy_gc */ |
NULL, /* flush_gc */ |
NULL, /* free_gc */ |
NULL, /* create_font */ |
NULL, /* free_font */ |
__glXCloseDisplay, /* close_display */ |
NULL, /* wire_to_event */ |
NULL, /* event_to_wire */ |
NULL, /* error */ |
NULL, /* error_string */ |
}; |
|
static XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo, |
__glXExtensionName, &__glXExtensionHooks, |
__GLX_NUMBER_EVENTS, NULL) |
|
static GLint |
_gl_convert_from_x_visual_type(int visualType) |
{ |
#define NUM_VISUAL_TYPES 6 |
static const int glx_visual_types[NUM_VISUAL_TYPES] = { |
GLX_STATIC_GRAY, GLX_GRAY_SCALE, |
GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, |
GLX_TRUE_COLOR, GLX_DIRECT_COLOR |
}; |
|
return ((unsigned) visualType < NUM_VISUAL_TYPES) |
? glx_visual_types[visualType] : GLX_NONE; |
} |
|
static void |
_gl_context_modes_destroy(__GLcontextModes * modes) |
{ |
while (modes != NULL) { |
__GLcontextModes *const next = modes->next; |
|
free(modes); |
modes = next; |
} |
} |
|
static __GLcontextModes * |
_gl_context_modes_create(unsigned count, size_t minimum_size) |
{ |
const size_t size = (minimum_size > sizeof(__GLcontextModes)) |
? minimum_size : sizeof(__GLcontextModes); |
__GLcontextModes *base = NULL; |
__GLcontextModes **next; |
unsigned i; |
|
next = &base; |
for (i = 0; i < count; i++) { |
*next = malloc(size); |
if (*next == NULL) { |
_gl_context_modes_destroy(base); |
base = NULL; |
break; |
} |
|
memset(*next, 0, size); |
(*next)->visualID = GLX_DONT_CARE; |
(*next)->visualType = GLX_DONT_CARE; |
(*next)->visualRating = GLX_NONE; |
(*next)->transparentPixel = GLX_NONE; |
(*next)->transparentRed = GLX_DONT_CARE; |
(*next)->transparentGreen = GLX_DONT_CARE; |
(*next)->transparentBlue = GLX_DONT_CARE; |
(*next)->transparentAlpha = GLX_DONT_CARE; |
(*next)->transparentIndex = GLX_DONT_CARE; |
(*next)->xRenderable = GLX_DONT_CARE; |
(*next)->fbconfigID = GLX_DONT_CARE; |
(*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; |
(*next)->bindToTextureRgb = GLX_DONT_CARE; |
(*next)->bindToTextureRgba = GLX_DONT_CARE; |
(*next)->bindToMipmapTexture = GLX_DONT_CARE; |
(*next)->bindToTextureTargets = GLX_DONT_CARE; |
(*next)->yInverted = GLX_DONT_CARE; |
|
next = &((*next)->next); |
} |
|
return base; |
} |
|
static char * |
__glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name) |
{ |
xGLXGenericGetStringReq *req; |
xGLXSingleReply reply; |
int length; |
int numbytes; |
char *buf; |
CARD32 for_whom = screen; |
CARD32 glxCode = X_GLXQueryServerString; |
|
|
LockDisplay(dpy); |
|
|
/* All of the GLX protocol requests for getting a string from the server |
* look the same. The exact meaning of the for_whom field is usually |
* either the screen number (for glXQueryServerString) or the context tag |
* (for GLXSingle). |
*/ |
|
GetReq(GLXGenericGetString, req); |
req->reqType = opcode; |
req->glxCode = glxCode; |
req->for_whom = for_whom; |
req->name = name; |
|
_XReply(dpy, (xReply *) & reply, 0, False); |
|
length = reply.length * 4; |
numbytes = reply.size; |
|
buf = malloc(numbytes); |
if (buf != NULL) { |
_XRead(dpy, buf, numbytes); |
length -= numbytes; |
} |
|
_XEatData(dpy, length); |
|
UnlockDisplay(dpy); |
SyncHandle(); |
|
return buf; |
} |
|
/************************************************************************/ |
/* |
** Free the per screen configs data as well as the array of |
** __glXScreenConfigs. |
*/ |
static void |
FreeScreenConfigs(__GLXdisplayPrivate * priv) |
{ |
__GLXscreenConfigs *psc; |
GLint i, screens; |
|
/* Free screen configuration information */ |
screens = ScreenCount(priv->dpy); |
for (i = 0; i < screens; i++) { |
psc = priv->screenConfigs[i]; |
if (!psc) |
continue; |
if (psc->configs) { |
_gl_context_modes_destroy(psc->configs); |
psc->configs = NULL; /* NOTE: just for paranoia */ |
} |
free((char *) psc->serverGLXexts); |
} |
free((char *) priv->screenConfigs); |
priv->screenConfigs = NULL; |
} |
|
/* |
** Release the private memory referred to in a display private |
** structure. The caller will free the extension structure. |
*/ |
static int |
__glXFreeDisplayPrivate(XExtData * extension) |
{ |
__GLXdisplayPrivate *priv; |
|
priv = (__GLXdisplayPrivate *) extension->private_data; |
FreeScreenConfigs(priv); |
free((char *) priv->serverGLXversion); |
free((char *) priv); |
return 0; |
} |
|
/************************************************************************/ |
|
/* |
** Query the version of the GLX extension. This procedure works even if |
** the client extension is not completely set up. |
*/ |
|
#define GLX_MAJOR_VERSION 1 /* current version numbers */ |
#define GLX_MINOR_VERSION 4 |
|
static Bool |
QueryVersion(Display * dpy, int opcode, int *major, int *minor) |
{ |
xGLXQueryVersionReq *req; |
xGLXQueryVersionReply reply; |
|
/* Send the glXQueryVersion request */ |
LockDisplay(dpy); |
GetReq(GLXQueryVersion, req); |
req->reqType = opcode; |
req->glxCode = X_GLXQueryVersion; |
req->majorVersion = GLX_MAJOR_VERSION; |
req->minorVersion = GLX_MINOR_VERSION; |
_XReply(dpy, (xReply *) & reply, 0, False); |
UnlockDisplay(dpy); |
SyncHandle(); |
|
if (reply.majorVersion != GLX_MAJOR_VERSION) { |
/* |
** The server does not support the same major release as this |
** client. |
*/ |
return GL_FALSE; |
} |
*major = reply.majorVersion; |
*minor = min(reply.minorVersion, GLX_MINOR_VERSION); |
return GL_TRUE; |
} |
|
#define __GLX_MIN_CONFIG_PROPS 18 |
#define __GLX_MAX_CONFIG_PROPS 500 |
#define __GLX_EXT_CONFIG_PROPS 10 |
#define __GLX_TOTAL_CONFIG (__GLX_MIN_CONFIG_PROPS + \ |
2 * __GLX_EXT_CONFIG_PROPS) |
|
static void |
__glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count, |
const INT32 * bp, Bool tagged_only, |
Bool fbconfig_style_tags) |
{ |
int i; |
|
if (!tagged_only) { |
/* Copy in the first set of properties */ |
config->visualID = *bp++; |
|
config->visualType = _gl_convert_from_x_visual_type(*bp++); |
|
config->rgbMode = *bp++; |
|
config->redBits = *bp++; |
config->greenBits = *bp++; |
config->blueBits = *bp++; |
config->alphaBits = *bp++; |
config->accumRedBits = *bp++; |
config->accumGreenBits = *bp++; |
config->accumBlueBits = *bp++; |
config->accumAlphaBits = *bp++; |
|
config->doubleBufferMode = *bp++; |
config->stereoMode = *bp++; |
|
config->rgbBits = *bp++; |
config->depthBits = *bp++; |
config->stencilBits = *bp++; |
config->numAuxBuffers = *bp++; |
config->level = *bp++; |
|
count -= __GLX_MIN_CONFIG_PROPS; |
} |
|
/* |
** Additional properties may be in a list at the end |
** of the reply. They are in pairs of property type |
** and property value. |
*/ |
|
#define FETCH_OR_SET(tag) \ |
config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1 |
|
for (i = 0; i < count; i += 2) { |
switch (*bp++) { |
case GLX_RGBA: |
FETCH_OR_SET(rgbMode); |
break; |
case GLX_BUFFER_SIZE: |
config->rgbBits = *bp++; |
break; |
case GLX_LEVEL: |
config->level = *bp++; |
break; |
case GLX_DOUBLEBUFFER: |
FETCH_OR_SET(doubleBufferMode); |
break; |
case GLX_STEREO: |
FETCH_OR_SET(stereoMode); |
break; |
case GLX_AUX_BUFFERS: |
config->numAuxBuffers = *bp++; |
break; |
case GLX_RED_SIZE: |
config->redBits = *bp++; |
break; |
case GLX_GREEN_SIZE: |
config->greenBits = *bp++; |
break; |
case GLX_BLUE_SIZE: |
config->blueBits = *bp++; |
break; |
case GLX_ALPHA_SIZE: |
config->alphaBits = *bp++; |
break; |
case GLX_DEPTH_SIZE: |
config->depthBits = *bp++; |
break; |
case GLX_STENCIL_SIZE: |
config->stencilBits = *bp++; |
break; |
case GLX_ACCUM_RED_SIZE: |
config->accumRedBits = *bp++; |
break; |
case GLX_ACCUM_GREEN_SIZE: |
config->accumGreenBits = *bp++; |
break; |
case GLX_ACCUM_BLUE_SIZE: |
config->accumBlueBits = *bp++; |
break; |
case GLX_ACCUM_ALPHA_SIZE: |
config->accumAlphaBits = *bp++; |
break; |
case GLX_VISUAL_CAVEAT_EXT: |
config->visualRating = *bp++; |
break; |
case GLX_X_VISUAL_TYPE: |
config->visualType = *bp++; |
break; |
case GLX_TRANSPARENT_TYPE: |
config->transparentPixel = *bp++; |
break; |
case GLX_TRANSPARENT_INDEX_VALUE: |
config->transparentIndex = *bp++; |
break; |
case GLX_TRANSPARENT_RED_VALUE: |
config->transparentRed = *bp++; |
break; |
case GLX_TRANSPARENT_GREEN_VALUE: |
config->transparentGreen = *bp++; |
break; |
case GLX_TRANSPARENT_BLUE_VALUE: |
config->transparentBlue = *bp++; |
break; |
case GLX_TRANSPARENT_ALPHA_VALUE: |
config->transparentAlpha = *bp++; |
break; |
case GLX_VISUAL_ID: |
config->visualID = *bp++; |
break; |
case GLX_DRAWABLE_TYPE: |
config->drawableType = *bp++; |
break; |
case GLX_RENDER_TYPE: |
config->renderType = *bp++; |
break; |
case GLX_X_RENDERABLE: |
config->xRenderable = *bp++; |
break; |
case GLX_FBCONFIG_ID: |
config->fbconfigID = *bp++; |
break; |
case GLX_MAX_PBUFFER_WIDTH: |
config->maxPbufferWidth = *bp++; |
break; |
case GLX_MAX_PBUFFER_HEIGHT: |
config->maxPbufferHeight = *bp++; |
break; |
case GLX_MAX_PBUFFER_PIXELS: |
config->maxPbufferPixels = *bp++; |
break; |
case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: |
config->optimalPbufferWidth = *bp++; |
break; |
case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: |
config->optimalPbufferHeight = *bp++; |
break; |
case GLX_VISUAL_SELECT_GROUP_SGIX: |
config->visualSelectGroup = *bp++; |
break; |
case GLX_SWAP_METHOD_OML: |
config->swapMethod = *bp++; |
break; |
case GLX_SAMPLE_BUFFERS_SGIS: |
config->sampleBuffers = *bp++; |
break; |
case GLX_SAMPLES_SGIS: |
config->samples = *bp++; |
break; |
case GLX_BIND_TO_TEXTURE_RGB_EXT: |
config->bindToTextureRgb = *bp++; |
break; |
case GLX_BIND_TO_TEXTURE_RGBA_EXT: |
config->bindToTextureRgba = *bp++; |
break; |
case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: |
config->bindToMipmapTexture = *bp++; |
break; |
case GLX_BIND_TO_TEXTURE_TARGETS_EXT: |
config->bindToTextureTargets = *bp++; |
break; |
case GLX_Y_INVERTED_EXT: |
config->yInverted = *bp++; |
break; |
case None: |
i = count; |
break; |
default: |
break; |
} |
} |
|
config->renderType = |
(config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; |
|
config->haveAccumBuffer = ((config->accumRedBits + |
config->accumGreenBits + |
config->accumBlueBits + |
config->accumAlphaBits) > 0); |
config->haveDepthBuffer = (config->depthBits > 0); |
config->haveStencilBuffer = (config->stencilBits > 0); |
} |
|
static __GLcontextModes * |
createConfigsFromProperties(Display * dpy, int nvisuals, int nprops, |
int screen, GLboolean tagged_only) |
{ |
INT32 buf[__GLX_TOTAL_CONFIG], *props; |
unsigned prop_size; |
__GLcontextModes *modes, *m; |
int i; |
|
if (nprops == 0) |
return NULL; |
|
/* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */ |
|
/* Check number of properties */ |
if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS) |
return NULL; |
|
/* Allocate memory for our config structure */ |
modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes)); |
if (!modes) |
return NULL; |
|
prop_size = nprops * __GLX_SIZE_INT32; |
if (prop_size <= sizeof(buf)) |
props = buf; |
else |
props = malloc(prop_size); |
|
/* Read each config structure and convert it into our format */ |
m = modes; |
for (i = 0; i < nvisuals; i++) { |
_XRead(dpy, (char *) props, prop_size); |
/* Older X servers don't send this so we default it here. */ |
m->drawableType = GLX_WINDOW_BIT; |
__glXInitializeVisualConfigFromTags(m, nprops, props, |
tagged_only, GL_TRUE); |
m->screen = screen; |
m = m->next; |
} |
|
if (props != buf) |
free(props); |
|
return modes; |
} |
|
static GLboolean |
getFBConfigs(__GLXscreenConfigs *psc, __GLXdisplayPrivate *priv, int screen) |
{ |
xGLXGetFBConfigsReq *fb_req; |
xGLXGetFBConfigsSGIXReq *sgi_req; |
xGLXVendorPrivateWithReplyReq *vpreq; |
xGLXGetFBConfigsReply reply; |
Display *dpy = priv->dpy; |
|
psc->serverGLXexts = |
__glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS); |
|
LockDisplay(dpy); |
|
psc->configs = NULL; |
if (atof(priv->serverGLXversion) >= 1.3) { |
GetReq(GLXGetFBConfigs, fb_req); |
fb_req->reqType = priv->majorOpcode; |
fb_req->glxCode = X_GLXGetFBConfigs; |
fb_req->screen = screen; |
} |
else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) { |
GetReqExtra(GLXVendorPrivateWithReply, |
sz_xGLXGetFBConfigsSGIXReq + |
sz_xGLXVendorPrivateWithReplyReq, vpreq); |
sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq; |
sgi_req->reqType = priv->majorOpcode; |
sgi_req->glxCode = X_GLXVendorPrivateWithReply; |
sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX; |
sgi_req->screen = screen; |
} |
else |
goto out; |
|
if (!_XReply(dpy, (xReply *) & reply, 0, False)) |
goto out; |
|
psc->configs = createConfigsFromProperties(dpy, |
reply.numFBConfigs, |
reply.numAttribs * 2, |
screen, GL_TRUE); |
|
out: |
UnlockDisplay(dpy); |
return psc->configs != NULL; |
} |
|
static GLboolean |
AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv) |
{ |
__GLXscreenConfigs *psc; |
GLint i, screens; |
|
/* |
** First allocate memory for the array of per screen configs. |
*/ |
screens = ScreenCount(dpy); |
priv->screenConfigs = malloc(screens * sizeof *priv->screenConfigs); |
if (!priv->screenConfigs) { |
return GL_FALSE; |
} |
|
priv->serverGLXversion = |
__glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION); |
if (priv->serverGLXversion == NULL) { |
FreeScreenConfigs(priv); |
return GL_FALSE; |
} |
|
for (i = 0; i < screens; i++) { |
psc = calloc(1, sizeof *psc); |
if (!psc) |
return GL_FALSE; |
getFBConfigs(psc, priv, i); |
priv->screenConfigs[i] = psc; |
} |
|
SyncHandle(); |
|
return GL_TRUE; |
} |
|
_X_HIDDEN __GLXdisplayPrivate * |
__glXInitialize(Display * dpy) |
{ |
XExtDisplayInfo *info = __glXFindDisplay(dpy); |
XExtData **privList, *private, *found; |
__GLXdisplayPrivate *dpyPriv; |
XEDataObject dataObj; |
int major, minor; |
|
if (!XextHasExtension(info)) |
return NULL; |
|
/* See if a display private already exists. If so, return it */ |
dataObj.display = dpy; |
privList = XEHeadOfExtensionList(dataObj); |
found = XFindOnExtensionList(privList, info->codes->extension); |
if (found) |
return (__GLXdisplayPrivate *) found->private_data; |
|
/* See if the versions are compatible */ |
if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor)) |
return NULL; |
|
/* |
** Allocate memory for all the pieces needed for this buffer. |
*/ |
private = malloc(sizeof(XExtData)); |
if (!private) |
return NULL; |
dpyPriv = calloc(1, sizeof(__GLXdisplayPrivate)); |
if (!dpyPriv) { |
free(private); |
return NULL; |
} |
|
/* |
** Init the display private and then read in the screen config |
** structures from the server. |
*/ |
dpyPriv->majorOpcode = info->codes->major_opcode; |
dpyPriv->dpy = dpy; |
|
if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) { |
free(dpyPriv); |
free(private); |
return NULL; |
} |
|
/* |
** Fill in the private structure. This is the actual structure that |
** hangs off of the Display structure. Our private structure is |
** referred to by this structure. Got that? |
*/ |
private->number = info->codes->extension; |
private->next = 0; |
private->free_private = __glXFreeDisplayPrivate; |
private->private_data = (char *) dpyPriv; |
XAddToExtensionList(privList, private); |
|
return dpyPriv; |
} |
|
#endif /* GLX_DIRECT_RENDERING */ |