summaryrefslogtreecommitdiffstats
path: root/src/glx/glx_pbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/glx_pbuffer.c')
-rw-r--r--src/glx/glx_pbuffer.c724
1 files changed, 724 insertions, 0 deletions
diff --git a/src/glx/glx_pbuffer.c b/src/glx/glx_pbuffer.c
new file mode 100644
index 00000000000..a0a02238b00
--- /dev/null
+++ b/src/glx/glx_pbuffer.c
@@ -0,0 +1,724 @@
+/*
+ * (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 <[email protected]>
+ */
+
+#include <inttypes.h>
+#include "glxclient.h"
+#include <X11/extensions/extutil.h>
+#include <X11/extensions/Xext.h>
+#include <assert.h>
+#include <string.h>
+#include "glxextensions.h"
+
+#define WARN_ONCE_GLX_1_3(a, b) { \
+ static int warned=1; \
+ if(warned) { \
+ warn_GLX_1_3((a), b ); \
+ warned=0; \
+ } \
+ }
+
+/**
+ * Emit a warning when clients use GLX 1.3 functions on pre-1.3 systems.
+ */
+static void
+warn_GLX_1_3(Display *dpy, const char *function_name)
+{
+ __GLXdisplayPrivate *priv = __glXInitialize(dpy);
+
+ if (priv->minorVersion < 3) {
+ fprintf(stderr,
+ "WARNING: Application calling GLX 1.3 function \"%s\" "
+ "when GLX 1.3 is not supported! This is an application bug!\n",
+ function_name);
+ }
+}
+
+
+/**
+ * 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;
+}
+
+
+static GLenum
+determineTextureFormat(const int *attribs, int numAttribs)
+{
+ int i;
+
+ for (i = 0; i < numAttribs; i++) {
+ if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT)
+ return attribs[2 * i + 1];
+ }
+
+ return 0;
+}
+#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;
+ GLboolean use_glx_1_3;
+
+ if ((dpy == NULL) || (drawable == 0)) {
+ return 0;
+ }
+
+ priv = __glXInitialize(dpy);
+ 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);
+ if (pdraw != NULL && !pdraw->textureFormat)
+ pdraw->textureFormat =
+ determineTextureFormat((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);
+ pdraw->textureFormat = determineTextureFormat(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;
+
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+
+ 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)
+{
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+ 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)
+{
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+
+ return CreateDrawable(dpy, (__GLcontextModes *) config,
+ (Drawable) pixmap, attrib_list, X_GLXCreatePixmap);
+}
+
+
+PUBLIC GLXWindow
+glXCreateWindow(Display * dpy, GLXFBConfig config, Window win,
+ const int *attrib_list)
+{
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+
+ return CreateDrawable(dpy, (__GLcontextModes *) config,
+ (Drawable) win, attrib_list, X_GLXCreateWindow);
+}
+
+
+PUBLIC void
+glXDestroyPixmap(Display * dpy, GLXPixmap pixmap)
+{
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+
+ DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap);
+}
+
+
+PUBLIC void
+glXDestroyWindow(Display * dpy, GLXWindow win)
+{
+ WARN_ONCE_GLX_1_3(dpy, __func__);
+
+ 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)
+