blob: 0f878f223f806d58974213ed4bb618042600d331 [file] [log] [blame]
/*
* (C) Copyright IBM Corporation 2004
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* \file glx_pbuffer.c
* Implementation of pbuffer related functions.
*
* \author Ian Romanick <idr@us.ibm.com>
*/
#include <inttypes.h>
#include "glxclient.h"
#include <X11/extensions/extutil.h>
#include <X11/extensions/Xext.h>
#include <assert.h>
#include <string.h>
#include "glapi.h"
#include "glxextensions.h"
#include "glcontextmodes.h"
#include "glheader.h"
/**
* Change a drawable's attribute.
*
* This function is used to implement \c glXSelectEvent and
* \c glXSelectEventSGIX.
*
* \note
* This function dynamically determines whether to use the SGIX_pbuffer
* version of the protocol or the GLX 1.3 version of the protocol.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static void
ChangeDrawableAttribute( Display * dpy, GLXDrawable drawable,
const CARD32 * attribs, size_t num_attribs )
{
__GLXdisplayPrivate *priv = __glXInitialize(dpy);
CARD32 * output;
CARD8 opcode;
if ( (dpy == NULL) || (drawable == 0) ) {
return;
}
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return;
LockDisplay(dpy);
if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
xGLXChangeDrawableAttributesReq *req;
GetReqExtra( GLXChangeDrawableAttributes, 8 + (8 * num_attribs), req );
output = (CARD32 *) (req + 1);
req->reqType = opcode;
req->glxCode = X_GLXChangeDrawableAttributes;
req->drawable = drawable;
req->numAttribs = (CARD32) num_attribs;
}
else {
xGLXVendorPrivateWithReplyReq *vpreq;
GetReqExtra( GLXVendorPrivateWithReply, 4 + (8 * num_attribs), vpreq );
output = (CARD32 *) (vpreq + 1);
vpreq->reqType = opcode;
vpreq->glxCode = X_GLXVendorPrivateWithReply;
vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX;
output[0] = (CARD32) drawable;
output++;
}
(void) memcpy( output, attribs, sizeof( CARD32 ) * 2 * num_attribs );
UnlockDisplay(dpy);
SyncHandle();
return;
}
/**
* Destroy a pbuffer.
*
* This function is used to implement \c glXDestroyPbuffer and
* \c glXDestroyGLXPbufferSGIX.
*
* \note
* This function dynamically determines whether to use the SGIX_pbuffer
* version of the protocol or the GLX 1.3 version of the protocol.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static void
DestroyPbuffer( Display * dpy, GLXDrawable drawable )
{
__GLXdisplayPrivate *priv = __glXInitialize(dpy);
CARD8 opcode;
if ( (dpy == NULL) || (drawable == 0) ) {
return;
}
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return;
LockDisplay(dpy);
if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
xGLXDestroyPbufferReq * req;
GetReq( GLXDestroyPbuffer, req );
req->reqType = opcode;
req->glxCode = X_GLXDestroyPbuffer;
req->pbuffer = (GLXPbuffer) drawable;
}
else {
xGLXVendorPrivateWithReplyReq *vpreq;
CARD32 * data;
GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
data = (CARD32 *) (vpreq + 1);
data[0] = (CARD32) drawable;
vpreq->reqType = opcode;
vpreq->glxCode = X_GLXVendorPrivateWithReply;
vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
}
UnlockDisplay(dpy);
SyncHandle();
return;
}
#ifdef GLX_DIRECT_RENDERING
extern __GLXDRIdrawable *
GetGLXDRIDrawable(Display *dpy, GLXDrawable drawable, int * const scrn_num);
static GLenum
determineTextureTarget(const int *attribs, int numAttribs)
{
GLenum target = 0;
int i;
for (i = 0; i < numAttribs; i++) {
if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) {
switch (attribs[2 * i + 1]) {
case GLX_TEXTURE_2D_EXT:
target = GL_TEXTURE_2D;
break;
case GLX_TEXTURE_RECTANGLE_EXT:
target = GL_TEXTURE_RECTANGLE_ARB;
break;
}
}
}
return target;
}
#endif
/**
* Get a drawable's attribute.
*
* This function is used to implement \c glXGetSelectedEvent and
* \c glXGetSelectedEventSGIX.
*
* \note
* This function dynamically determines whether to use the SGIX_pbuffer
* version of the protocol or the GLX 1.3 version of the protocol.
*
* \todo
* The number of attributes returned is likely to be small, probably less than
* 10. Given that, this routine should try to use an array on the stack to
* capture the reply rather than always calling Xmalloc.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static int
GetDrawableAttribute( Display *dpy, GLXDrawable drawable,
int attribute, unsigned int *value )
{
__GLXdisplayPrivate *priv;
xGLXGetDrawableAttributesReply reply;
CARD32 * data;
CARD8 opcode;
unsigned int length;
unsigned int i;
unsigned int num_attributes;
if ( (dpy == NULL) || (drawable == 0) ) {
return 0;
}
priv = __glXInitialize(dpy);
GLboolean use_glx_1_3 = ((priv->majorVersion > 1)
|| (priv->minorVersion >= 3));
*value = 0;
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return 0;
LockDisplay(dpy);
if ( use_glx_1_3 ) {
xGLXGetDrawableAttributesReq *req;
GetReqExtra( GLXGetDrawableAttributes, 4, req );
req->reqType = opcode;
req->glxCode = X_GLXGetDrawableAttributes;
req->drawable = drawable;
}
else {
xGLXVendorPrivateWithReplyReq *vpreq;
GetReqExtra( GLXVendorPrivateWithReply, 4, vpreq );
data = (CARD32 *) (vpreq + 1);
data[0] = (CARD32) drawable;
vpreq->reqType = opcode;
vpreq->glxCode = X_GLXVendorPrivateWithReply;
vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
}
_XReply(dpy, (xReply*) &reply, 0, False);
if (reply.type == X_Error)
{
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
length = reply.length;
if (length)
{
num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
data = (CARD32 *) Xmalloc( length * sizeof(CARD32) );
if ( data == NULL ) {
/* Throw data on the floor */
_XEatData(dpy, length);
} else {
_XRead(dpy, (char *)data, length * sizeof(CARD32) );
/* Search the set of returned attributes for the attribute requested by
* the caller.
*/
for ( i = 0 ; i < num_attributes ; i++ ) {
if ( data[i*2] == attribute ) {
*value = data[ (i*2) + 1 ];
break;
}
}
#ifdef GLX_DIRECT_RENDERING
{
__GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, NULL);
if (pdraw != NULL && !pdraw->textureTarget)
pdraw->textureTarget = determineTextureTarget((const int *)data,
num_attributes);
}
#endif
Xfree( data );
}
}
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
/**
* Create a non-pbuffer GLX drawable.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static GLXDrawable
CreateDrawable( Display *dpy, const __GLcontextModes * fbconfig,
Drawable drawable, const int *attrib_list,
CARD8 glxCode )
{
xGLXCreateWindowReq * req;
CARD32 * data;
unsigned int i;
CARD8 opcode;
i = 0;
if (attrib_list) {
while (attrib_list[i * 2] != None)
i++;
}
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return None;
LockDisplay(dpy);
GetReqExtra( GLXCreateWindow, 8 * i, req );
data = (CARD32 *) (req + 1);
req->reqType = opcode;
req->glxCode = glxCode;
req->screen = (CARD32) fbconfig->screen;
req->fbconfig = fbconfig->fbconfigID;
req->window = (CARD32) drawable;
req->glxwindow = (GLXWindow) XAllocID(dpy);
req->numAttribs = (CARD32) i;
memcpy( data, attrib_list, 8 * i );
UnlockDisplay(dpy);
SyncHandle();
#ifdef GLX_DIRECT_RENDERING
do {
/* FIXME: Maybe delay __DRIdrawable creation until the drawable
* is actually bound to a context... */
__GLXdisplayPrivate * const priv = __glXInitialize(dpy);
__GLXDRIdrawable *pdraw;
__GLXscreenConfigs *psc;
psc = &priv->screenConfigs[fbconfig->screen];
if (psc->driScreen == NULL)
break;
pdraw = psc->driScreen->createDrawable(psc, drawable,
req->glxwindow, fbconfig);
if (pdraw == NULL) {
fprintf(stderr, "failed to create drawable\n");
break;
}
if (__glxHashInsert(psc->drawHash, req->glxwindow, pdraw)) {
(*pdraw->destroyDrawable)(pdraw);
return None; /* FIXME: Check what we're supposed to do here... */
}
pdraw->textureTarget = determineTextureTarget(attrib_list, i);
} while (0);
#endif
return (GLXDrawable)req->glxwindow;
}
/**
* Destroy a non-pbuffer GLX drawable.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static void
DestroyDrawable( Display * dpy, GLXDrawable drawable, CARD32 glxCode )
{
xGLXDestroyPbufferReq * req;
CARD8 opcode;
if ( (dpy == NULL) || (drawable == 0) ) {
return;
}
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return;
LockDisplay(dpy);
GetReqExtra( GLXDestroyPbuffer, 4, req );
req->reqType = opcode;
req->glxCode = glxCode;
req->pbuffer = (GLXPbuffer) drawable;
UnlockDisplay(dpy);
SyncHandle();
#ifdef GLX_DIRECT_RENDERING
{
int screen;
__GLXdisplayPrivate * const priv = __glXInitialize(dpy);
__GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, &screen);
__GLXscreenConfigs *psc = &priv->screenConfigs[screen];
if (pdraw != NULL) {
(*pdraw->destroyDrawable)(pdraw);
__glxHashDelete(psc->drawHash, drawable);
}
}
#endif
return;
}
/**
* Create a pbuffer.
*
* This function is used to implement \c glXCreatePbuffer and
* \c glXCreateGLXPbufferSGIX.
*
* \note
* This function dynamically determines whether to use the SGIX_pbuffer
* version of the protocol or the GLX 1.3 version of the protocol.
*
* \todo
* This function needs to be modified to work with direct-rendering drivers.
*/
static GLXDrawable
CreatePbuffer( Display *dpy, const __GLcontextModes * fbconfig,
unsigned int width, unsigned int height,
const int *attrib_list, GLboolean size_in_attribs )
{
__GLXdisplayPrivate *priv = __glXInitialize(dpy);
GLXDrawable id = 0;
CARD32 * data;
CARD8 opcode;
unsigned int i;
i = 0;
if (attrib_list) {
while (attrib_list[i * 2])
i++;
}
opcode = __glXSetupForCommand(dpy);
if (!opcode)
return None;
LockDisplay(dpy);
id = XAllocID(dpy);
if ( (priv->majorVersion > 1) || (priv->minorVersion >= 3) ) {
xGLXCreatePbufferReq * req;
unsigned int extra = (size_in_attribs) ? 0 : 2;
GetReqExtra( GLXCreatePbuffer, (8 * (i + extra)), req );
data = (CARD32 *) (req + 1);
req->reqType = opcode;
req->glxCode = X_GLXCreatePbuffer;
req->screen = (CARD32) fbconfig->screen;
req->fbconfig = fbconfig->fbconfigID;
req->pbuffer = (GLXPbuffer) id;
req->numAttribs = (CARD32) (i + extra);
if ( ! size_in_attribs ) {
data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
data[(2 * i) + 1] = width;
data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
data[(2 * i) + 3] = height;
data += 4;
}
}
else {
xGLXVendorPrivateReq *vpreq;
GetReqExtra( GLXVendorPrivate, 20 + (8 * i), vpreq );
data = (CARD32 *) (vpreq + 1);
vpreq->reqType = opcode;
vpreq->glxCode = X_GLXVendorPrivate;
vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
data[0] = (CARD32) fbconfig->screen;
data[1] = (CARD32) fbconfig->fbconfigID;
data[2] = (CARD32) id;
data[3] = (CARD32) width;
data[4] = (CARD32) height;
data += 5;
}
(void) memcpy( data, attrib_list, sizeof(CARD32) * 2 * i );
UnlockDisplay(dpy);
SyncHandle();
return id;
}
/**
* Create a new pbuffer.
*/
PUBLIC GLXPbufferSGIX
glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config,
unsigned int width, unsigned int height,
int *attrib_list)
{
return (GLXPbufferSGIX) CreatePbuffer( dpy, (__GLcontextModes *) config,
width, height,
attrib_list, GL_FALSE );
}
/**
* Create a new pbuffer.
*/
PUBLIC GLXPbuffer
glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attrib_list)
{
int i, width, height;
width = 0;
height = 0;
for (i = 0; attrib_list[i * 2]; i++) {
switch (attrib_list[i * 2]) {
case GLX_PBUFFER_WIDTH:
width = attrib_list[i * 2 + 1];
break;
case GLX_PBUFFER_HEIGHT:
height = attrib_list[i * 2 + 1];
break;
}
}
return (GLXPbuffer) CreatePbuffer( dpy, (__GLcontextModes *) config,
width, height,
attrib_list, GL_TRUE );
}
/**
* Destroy an existing pbuffer.
*/
PUBLIC void
glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
{
DestroyPbuffer( dpy, pbuf );
}
/**
* Query an attribute of a drawable.
*/
PUBLIC void
glXQueryDrawable(Display *dpy, GLXDrawable drawable,
int attribute, unsigned int *value)
{
GetDrawableAttribute( dpy, drawable, attribute, value );
}
/**
* Query an attribute of a pbuffer.
*/
PUBLIC int
glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX drawable,
int attribute, unsigned int *value)
{
return GetDrawableAttribute( dpy, drawable, attribute, value );
}
/**
* Select the event mask for a drawable.
*/
PUBLIC void
glXSelectEvent(Display *dpy, GLXDrawable drawable, unsigned long mask)
{
CARD32 attribs[2];
attribs[0] = (CARD32) GLX_EVENT_MASK;
attribs[1] = (CARD32) mask;
ChangeDrawableAttribute( dpy, drawable, attribs, 1 );
}
/**
* Get the selected event mask for a drawable.
*/
PUBLIC void
glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask)
{
unsigned int value;
/* The non-sense with value is required because on LP64 platforms
* sizeof(unsigned int) != sizeof(unsigned long). On little-endian
* we could just type-cast the pointer, but why?
*/
GetDrawableAttribute( dpy, drawable, GLX_EVENT_MASK_SGIX, & value );
*mask = value;
}
PUBLIC GLXPixmap
glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap,
const int *attrib_list )
{
return CreateDrawable( dpy, (__GLcontextModes *) config,
(Drawable) pixmap, attrib_list,
X_GLXCreatePixmap );
}
PUBLIC GLXWindow
glXCreateWindow( Display *dpy, GLXFBConfig config, Window win,
const int *attrib_list )
{
return CreateDrawable( dpy, (__GLcontextModes *) config,
(Drawable) win, attrib_list,
X_GLXCreateWindow );
}
PUBLIC void
glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
{
DestroyDrawable( dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap );
}
PUBLIC void
glXDestroyWindow(Display *dpy, GLXWindow win)
{
DestroyDrawable( dpy, (GLXDrawable) win, X_GLXDestroyWindow );
}
PUBLIC GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
(Display *dpy, GLXPbufferSGIX pbuf),
(dpy, pbuf),
glXDestroyPbuffer)
PUBLIC GLX_ALIAS_VOID(glXSelectEventSGIX,
(Display *dpy, GLXDrawable drawable, unsigned long mask),
(dpy, drawable, mask),
glXSelectEvent)
PUBLIC GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
(Display *dpy, GLXDrawable drawable, unsigned long *mask),
(dpy, drawable, mask),
glXGetSelectedEvent)