glx_pbuffer.c revision d5aee174b88878e6d47dc1fadd3935f535fd85f0
1/*
2 * (C) Copyright IBM Corporation 2004
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file glx_pbuffer.c
27 * Implementation of pbuffer related functions.
28 *
29 * \author Ian Romanick <idr@us.ibm.com>
30 */
31
32#include <inttypes.h>
33#include "glxclient.h"
34#include <X11/extensions/extutil.h>
35#include <X11/extensions/Xext.h>
36#include <assert.h>
37#include <string.h>
38#include "glxextensions.h"
39
40#ifdef GLX_USE_APPLEGL
41#include <pthread.h>
42#include "apple_glx_drawable.h"
43#endif
44
45#include "glx_error.h"
46
47#define WARN_ONCE_GLX_1_3(a, b) {		\
48		static int warned=1;		\
49		if(warned) {			\
50			warn_GLX_1_3((a), b );	\
51			warned=0;		\
52		}				\
53	}
54
55/**
56 * Emit a warning when clients use GLX 1.3 functions on pre-1.3 systems.
57 */
58static void
59warn_GLX_1_3(Display * dpy, const char *function_name)
60{
61   struct glx_display *priv = __glXInitialize(dpy);
62
63   if (priv->minorVersion < 3) {
64      fprintf(stderr,
65              "WARNING: Application calling GLX 1.3 function \"%s\" "
66              "when GLX 1.3 is not supported!  This is an application bug!\n",
67              function_name);
68   }
69}
70
71#ifndef GLX_USE_APPLEGL
72/**
73 * Change a drawable's attribute.
74 *
75 * This function is used to implement \c glXSelectEvent and
76 * \c glXSelectEventSGIX.
77 *
78 * \note
79 * This function dynamically determines whether to use the SGIX_pbuffer
80 * version of the protocol or the GLX 1.3 version of the protocol.
81 */
82static void
83ChangeDrawableAttribute(Display * dpy, GLXDrawable drawable,
84                        const CARD32 * attribs, size_t num_attribs)
85{
86   struct glx_display *priv = __glXInitialize(dpy);
87#ifdef GLX_DIRECT_RENDERING
88   __GLXDRIdrawable *pdraw;
89#endif
90   CARD32 *output;
91   CARD8 opcode;
92   int i;
93
94   if ((dpy == NULL) || (drawable == 0)) {
95      return;
96   }
97
98   opcode = __glXSetupForCommand(dpy);
99   if (!opcode)
100      return;
101
102   LockDisplay(dpy);
103
104   if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
105      xGLXChangeDrawableAttributesReq *req;
106
107      GetReqExtra(GLXChangeDrawableAttributes, 8 * num_attribs, req);
108      output = (CARD32 *) (req + 1);
109
110      req->reqType = opcode;
111      req->glxCode = X_GLXChangeDrawableAttributes;
112      req->drawable = drawable;
113      req->numAttribs = (CARD32) num_attribs;
114   }
115   else {
116      xGLXVendorPrivateWithReplyReq *vpreq;
117
118      GetReqExtra(GLXVendorPrivateWithReply, 8 + (8 * num_attribs), vpreq);
119      output = (CARD32 *) (vpreq + 1);
120
121      vpreq->reqType = opcode;
122      vpreq->glxCode = X_GLXVendorPrivateWithReply;
123      vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX;
124
125      output[0] = (CARD32) drawable;
126      output[1] = num_attribs;
127      output += 2;
128   }
129
130   (void) memcpy(output, attribs, sizeof(CARD32) * 2 * num_attribs);
131
132   UnlockDisplay(dpy);
133   SyncHandle();
134
135#ifdef GLX_DIRECT_RENDERING
136   pdraw = GetGLXDRIDrawable(dpy, drawable);
137
138   if (!pdraw)
139      return;
140
141   for (i = 0; i < num_attribs; i++) {
142      switch(attribs[i * 2]) {
143      case GLX_EVENT_MASK:
144	 /* Keep a local copy for masking out DRI2 proto events as needed */
145	 pdraw->eventMask = attribs[i * 2 + 1];
146	 break;
147      }
148   }
149#endif
150
151   return;
152}
153
154
155#ifdef GLX_DIRECT_RENDERING
156static GLenum
157determineTextureTarget(const int *attribs, int numAttribs)
158{
159   GLenum target = 0;
160   int i;
161
162   for (i = 0; i < numAttribs; i++) {
163      if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) {
164         switch (attribs[2 * i + 1]) {
165         case GLX_TEXTURE_2D_EXT:
166            target = GL_TEXTURE_2D;
167            break;
168         case GLX_TEXTURE_RECTANGLE_EXT:
169            target = GL_TEXTURE_RECTANGLE_ARB;
170            break;
171         }
172      }
173   }
174
175   return target;
176}
177
178static GLenum
179determineTextureFormat(const int *attribs, int numAttribs)
180{
181   int i;
182
183   for (i = 0; i < numAttribs; i++) {
184      if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT)
185         return attribs[2 * i + 1];
186   }
187
188   return 0;
189}
190
191static GLboolean
192CreateDRIDrawable(Display *dpy, struct glx_config *config,
193		  XID drawable, XID glxdrawable,
194		  const int *attrib_list, size_t num_attribs)
195{
196   struct glx_display *const priv = __glXInitialize(dpy);
197   __GLXDRIdrawable *pdraw;
198   struct glx_screen *psc;
199
200   psc = priv->screens[config->screen];
201   if (psc->driScreen == NULL)
202      return GL_TRUE;
203
204   pdraw = psc->driScreen->createDrawable(psc, drawable,
205					  glxdrawable, config);
206   if (pdraw == NULL) {
207      fprintf(stderr, "failed to create drawable\n");
208      return GL_FALSE;
209   }
210
211   if (__glxHashInsert(priv->drawHash, glxdrawable, pdraw)) {
212      (*pdraw->destroyDrawable) (pdraw);
213      return GL_FALSE;
214   }
215
216   pdraw->textureTarget = determineTextureTarget(attrib_list, num_attribs);
217   pdraw->textureFormat = determineTextureFormat(attrib_list, num_attribs);
218
219   return GL_TRUE;
220}
221
222static void
223DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable)
224{
225   struct glx_display *const priv = __glXInitialize(dpy);
226   __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable);
227   XID xid;
228
229   if (pdraw != NULL) {
230      xid = pdraw->xDrawable;
231      (*pdraw->destroyDrawable) (pdraw);
232      __glxHashDelete(priv->drawHash, drawable);
233      if (destroy_xdrawable)
234         XFreePixmap(priv->dpy, xid);
235   }
236}
237
238#else
239
240static GLboolean
241CreateDRIDrawable(Display *dpy, const struct glx_config * fbconfig,
242		  XID drawable, XID glxdrawable,
243		  const int *attrib_list, size_t num_attribs)
244{
245    return GL_TRUE;
246}
247
248static void
249DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable)
250{
251}
252
253#endif
254
255/**
256 * Get a drawable's attribute.
257 *
258 * This function is used to implement \c glXGetSelectedEvent and
259 * \c glXGetSelectedEventSGIX.
260 *
261 * \note
262 * This function dynamically determines whether to use the SGIX_pbuffer
263 * version of the protocol or the GLX 1.3 version of the protocol.
264 *
265 * \todo
266 * The number of attributes returned is likely to be small, probably less than
267 * 10.  Given that, this routine should try to use an array on the stack to
268 * capture the reply rather than always calling Xmalloc.
269 */
270static int
271GetDrawableAttribute(Display * dpy, GLXDrawable drawable,
272                     int attribute, unsigned int *value)
273{
274   struct glx_display *priv;
275   xGLXGetDrawableAttributesReply reply;
276   CARD32 *data;
277   CARD8 opcode;
278   unsigned int length;
279   unsigned int i;
280   unsigned int num_attributes;
281   GLboolean use_glx_1_3;
282
283   if (dpy == NULL)
284      return 0;
285
286   /* Page 38 (page 52 of the PDF) of glxencode1.3.pdf says:
287    *
288    *     "If drawable is not a valid GLX drawable, a GLXBadDrawable error is
289    *     generated."
290    */
291   if (drawable == 0) {
292      __glXSendError(dpy, GLXBadDrawable, 0, X_GLXGetDrawableAttributes, false);
293      return 0;
294   }
295
296   priv = __glXInitialize(dpy);
297   use_glx_1_3 = ((priv->majorVersion > 1) || (priv->minorVersion >= 3));
298
299   *value = 0;
300
301
302   opcode = __glXSetupForCommand(dpy);
303   if (!opcode)
304      return 0;
305
306   LockDisplay(dpy);
307
308   if (use_glx_1_3) {
309      xGLXGetDrawableAttributesReq *req;
310
311      GetReq(GLXGetDrawableAttributes, req);
312      req->reqType = opcode;
313      req->glxCode = X_GLXGetDrawableAttributes;
314      req->drawable = drawable;
315   }
316   else {
317      xGLXVendorPrivateWithReplyReq *vpreq;
318
319      GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq);
320      data = (CARD32 *) (vpreq + 1);
321      data[0] = (CARD32) drawable;
322
323      vpreq->reqType = opcode;
324      vpreq->glxCode = X_GLXVendorPrivateWithReply;
325      vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
326   }
327
328   _XReply(dpy, (xReply *) & reply, 0, False);
329
330   if (reply.type == X_Error) {
331      UnlockDisplay(dpy);
332      SyncHandle();
333      return 0;
334   }
335
336   length = reply.length;
337   if (length) {
338      num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
339      data = malloc(length * sizeof(CARD32));
340      if (data == NULL) {
341         /* Throw data on the floor */
342         _XEatData(dpy, length);
343      }
344      else {
345         _XRead(dpy, (char *) data, length * sizeof(CARD32));
346
347         /* Search the set of returned attributes for the attribute requested by
348          * the caller.
349          */
350         for (i = 0; i < num_attributes; i++) {
351            if (data[i * 2] == attribute) {
352               *value = data[(i * 2) + 1];
353               break;
354            }
355         }
356
357#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
358         {
359            __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable);
360
361            if (pdraw != NULL && !pdraw->textureTarget)
362               pdraw->textureTarget =
363                  determineTextureTarget((const int *) data, num_attributes);
364            if (pdraw != NULL && !pdraw->textureFormat)
365               pdraw->textureFormat =
366                  determineTextureFormat((const int *) data, num_attributes);
367         }
368#endif
369
370         free(data);
371      }
372   }
373
374   UnlockDisplay(dpy);
375   SyncHandle();
376
377   return 0;
378}
379
380static void
381protocolDestroyDrawable(Display *dpy, GLXDrawable drawable, CARD32 glxCode)
382{
383   xGLXDestroyPbufferReq *req;
384   CARD8 opcode;
385
386   opcode = __glXSetupForCommand(dpy);
387   if (!opcode)
388      return;
389
390   LockDisplay(dpy);
391
392   GetReq(GLXDestroyPbuffer, req);
393   req->reqType = opcode;
394   req->glxCode = glxCode;
395   req->pbuffer = (GLXPbuffer) drawable;
396
397   UnlockDisplay(dpy);
398   SyncHandle();
399}
400
401/**
402 * Create a non-pbuffer GLX drawable.
403 */
404static GLXDrawable
405CreateDrawable(Display *dpy, struct glx_config *config,
406               Drawable drawable, const int *attrib_list, CARD8 glxCode)
407{
408   xGLXCreateWindowReq *req;
409   struct glx_drawable *glxDraw;
410   CARD32 *data;
411   unsigned int i;
412   CARD8 opcode;
413   GLXDrawable xid;
414
415   i = 0;
416   if (attrib_list) {
417      while (attrib_list[i * 2] != None)
418         i++;
419   }
420
421   opcode = __glXSetupForCommand(dpy);
422   if (!opcode)
423      return None;
424
425   glxDraw = malloc(sizeof(*glxDraw));
426   if (!glxDraw)
427      return None;
428
429   LockDisplay(dpy);
430   GetReqExtra(GLXCreateWindow, 8 * i, req);
431   data = (CARD32 *) (req + 1);
432
433   req->reqType = opcode;
434   req->glxCode = glxCode;
435   req->screen = config->screen;
436   req->fbconfig = config->fbconfigID;
437   req->window = drawable;
438   req->glxwindow = xid = XAllocID(dpy);
439   req->numAttribs = i;
440
441   if (attrib_list)
442      memcpy(data, attrib_list, 8 * i);
443
444   UnlockDisplay(dpy);
445   SyncHandle();
446
447   if (InitGLXDrawable(dpy, glxDraw, drawable, xid)) {
448      free(glxDraw);
449      return None;
450   }
451
452   if (!CreateDRIDrawable(dpy, config, drawable, xid, attrib_list, i)) {
453      if (glxCode == X_GLXCreatePixmap)
454         glxCode = X_GLXDestroyPixmap;
455      else
456         glxCode = X_GLXDestroyWindow;
457      protocolDestroyDrawable(dpy, xid, glxCode);
458      xid = None;
459   }
460
461   return xid;
462}
463
464
465/**
466 * Destroy a non-pbuffer GLX drawable.
467 */
468static void
469DestroyDrawable(Display * dpy, GLXDrawable drawable, CARD32 glxCode)
470{
471   if ((dpy == NULL) || (drawable == 0)) {
472      return;
473   }
474
475   protocolDestroyDrawable(dpy, drawable, glxCode);
476
477   DestroyGLXDrawable(dpy, drawable);
478   DestroyDRIDrawable(dpy, drawable, GL_FALSE);
479
480   return;
481}
482
483
484/**
485 * Create a pbuffer.
486 *
487 * This function is used to implement \c glXCreatePbuffer and
488 * \c glXCreateGLXPbufferSGIX.
489 *
490 * \note
491 * This function dynamically determines whether to use the SGIX_pbuffer
492 * version of the protocol or the GLX 1.3 version of the protocol.
493 */
494static GLXDrawable
495CreatePbuffer(Display * dpy, struct glx_config *config,
496              unsigned int width, unsigned int height,
497              const int *attrib_list, GLboolean size_in_attribs)
498{
499   struct glx_display *priv = __glXInitialize(dpy);
500   GLXDrawable id = 0;
501   CARD32 *data;
502   CARD8 opcode;
503   unsigned int i;
504   Pixmap pixmap;
505   GLboolean glx_1_3 = GL_FALSE;
506
507   i = 0;
508   if (attrib_list) {
509      while (attrib_list[i * 2])
510         i++;
511   }
512
513   opcode = __glXSetupForCommand(dpy);
514   if (!opcode)
515      return None;
516
517   LockDisplay(dpy);
518   id = XAllocID(dpy);
519
520   if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
521      xGLXCreatePbufferReq *req;
522      unsigned int extra = (size_in_attribs) ? 0 : 2;
523
524      glx_1_3 = GL_TRUE;
525
526      GetReqExtra(GLXCreatePbuffer, (8 * (i + extra)), req);
527      data = (CARD32 *) (req + 1);
528
529      req->reqType = opcode;
530      req->glxCode = X_GLXCreatePbuffer;
531      req->screen = config->screen;
532      req->fbconfig = config->fbconfigID;
533      req->pbuffer = id;
534      req->numAttribs = i + extra;
535
536      if (!size_in_attribs) {
537         data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
538         data[(2 * i) + 1] = width;
539         data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
540         data[(2 * i) + 3] = height;
541         data += 4;
542      }
543   }
544   else {
545      xGLXVendorPrivateReq *vpreq;
546
547      GetReqExtra(GLXVendorPrivate, 20 + (8 * i), vpreq);
548      data = (CARD32 *) (vpreq + 1);
549
550      vpreq->reqType = opcode;
551      vpreq->glxCode = X_GLXVendorPrivate;
552      vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
553
554      data[0] = config->screen;
555      data[1] = config->fbconfigID;
556      data[2] = id;
557      data[3] = width;
558      data[4] = height;
559      data += 5;
560   }
561
562   (void) memcpy(data, attrib_list, sizeof(CARD32) * 2 * i);
563
564   UnlockDisplay(dpy);
565   SyncHandle();
566
567   pixmap = XCreatePixmap(dpy, RootWindow(dpy, config->screen),
568			  width, height, config->rgbBits);
569
570   if (!CreateDRIDrawable(dpy, config, pixmap, id, attrib_list, i)) {
571      CARD32 o = glx_1_3 ? X_GLXDestroyPbuffer : X_GLXvop_DestroyGLXPbufferSGIX;
572      XFreePixmap(dpy, pixmap);
573      protocolDestroyDrawable(dpy, id, o);
574      id = None;
575   }
576
577   return id;
578}
579
580/**
581 * Destroy a pbuffer.
582 *
583 * This function is used to implement \c glXDestroyPbuffer and
584 * \c glXDestroyGLXPbufferSGIX.
585 *
586 * \note
587 * This function dynamically determines whether to use the SGIX_pbuffer
588 * version of the protocol or the GLX 1.3 version of the protocol.
589 */
590static void
591DestroyPbuffer(Display * dpy, GLXDrawable drawable)
592{
593   struct glx_display *priv = __glXInitialize(dpy);
594   CARD8 opcode;
595
596   if ((dpy == NULL) || (drawable == 0)) {
597      return;
598   }
599
600   opcode = __glXSetupForCommand(dpy);
601   if (!opcode)
602      return;
603
604   LockDisplay(dpy);
605
606   if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
607      xGLXDestroyPbufferReq *req;
608
609      GetReq(GLXDestroyPbuffer, req);
610      req->reqType = opcode;
611      req->glxCode = X_GLXDestroyPbuffer;
612      req->pbuffer = (GLXPbuffer) drawable;
613   }
614   else {
615      xGLXVendorPrivateWithReplyReq *vpreq;
616      CARD32 *data;
617
618      GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq);
619      data = (CARD32 *) (vpreq + 1);
620
621      data[0] = (CARD32) drawable;
622
623      vpreq->reqType = opcode;
624      vpreq->glxCode = X_GLXVendorPrivateWithReply;
625      vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
626   }
627
628   UnlockDisplay(dpy);
629   SyncHandle();
630
631   DestroyDRIDrawable(dpy, drawable, GL_TRUE);
632
633   return;
634}
635
636/**
637 * Create a new pbuffer.
638 */
639_X_EXPORT GLXPbufferSGIX
640glXCreateGLXPbufferSGIX(Display * dpy, GLXFBConfigSGIX config,
641                        unsigned int width, unsigned int height,
642                        int *attrib_list)
643{
644   return (GLXPbufferSGIX) CreatePbuffer(dpy, (struct glx_config *) config,
645                                         width, height,
646                                         attrib_list, GL_FALSE);
647}
648
649#endif /* GLX_USE_APPLEGL */
650
651/**
652 * Create a new pbuffer.
653 */
654_X_EXPORT GLXPbuffer
655glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int *attrib_list)
656{
657   int i, width, height;
658#ifdef GLX_USE_APPLEGL
659   GLXPbuffer result;
660   int errorcode;
661#endif
662
663   width = 0;
664   height = 0;
665
666   WARN_ONCE_GLX_1_3(dpy, __func__);
667
668#ifdef GLX_USE_APPLEGL
669   for (i = 0; attrib_list[i]; ++i) {
670      switch (attrib_list[i]) {
671      case GLX_PBUFFER_WIDTH:
672         width = attrib_list[i + 1];
673         ++i;
674         break;
675
676      case GLX_PBUFFER_HEIGHT:
677         height = attrib_list[i + 1];
678         ++i;
679         break;
680
681      case GLX_LARGEST_PBUFFER:
682         /* This is a hint we should probably handle, but how? */
683         ++i;
684         break;
685
686      case GLX_PRESERVED_CONTENTS:
687         /* The contents are always preserved with AppleSGLX with CGL. */
688         ++i;
689         break;
690
691      default:
692         return None;
693      }
694   }
695
696   if (apple_glx_pbuffer_create(dpy, config, width, height, &errorcode,
697                                &result)) {
698      /*
699       * apple_glx_pbuffer_create only sets the errorcode to core X11
700       * errors.
701       */
702      __glXSendError(dpy, errorcode, 0, X_GLXCreatePbuffer, true);
703
704      return None;
705   }
706
707   return result;
708#else
709   for (i = 0; attrib_list[i * 2]; i++) {
710      switch (attrib_list[i * 2]) {
711      case GLX_PBUFFER_WIDTH:
712         width = attrib_list[i * 2 + 1];
713         break;
714      case GLX_PBUFFER_HEIGHT:
715         height = attrib_list[i * 2 + 1];
716         break;
717      }
718   }
719
720   return (GLXPbuffer) CreatePbuffer(dpy, (struct glx_config *) config,
721                                     width, height, attrib_list, GL_TRUE);
722#endif
723}
724
725
726/**
727 * Destroy an existing pbuffer.
728 */
729_X_EXPORT void
730glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf)
731{
732#ifdef GLX_USE_APPLEGL
733   if (apple_glx_pbuffer_destroy(dpy, pbuf)) {
734      __glXSendError(dpy, GLXBadPbuffer, pbuf, X_GLXDestroyPbuffer, false);
735   }
736#else
737   DestroyPbuffer(dpy, pbuf);
738#endif
739}
740
741
742/**
743 * Query an attribute of a drawable.
744 */
745_X_EXPORT void
746glXQueryDrawable(Display * dpy, GLXDrawable drawable,
747                 int attribute, unsigned int *value)
748{
749   WARN_ONCE_GLX_1_3(dpy, __func__);
750#ifdef GLX_USE_APPLEGL
751   Window root;
752   int x, y;
753   unsigned int width, height, bd, depth;
754
755   if (apple_glx_pixmap_query(drawable, attribute, value))
756      return;                   /*done */
757
758   if (apple_glx_pbuffer_query(drawable, attribute, value))
759      return;                   /*done */
760
761   /*
762    * The OpenGL spec states that we should report GLXBadDrawable if
763    * the drawable is invalid, however doing so would require that we
764    * use XSetErrorHandler(), which is known to not be thread safe.
765    * If we use a round-trip call to validate the drawable, there could
766    * be a race, so instead we just opt in favor of letting the
767    * XGetGeometry request fail with a GetGeometry request X error
768    * rather than GLXBadDrawable, in what is hoped to be a rare
769    * case of an invalid drawable.  In practice most and possibly all
770    * X11 apps using GLX shouldn't notice a difference.
771    */
772   if (XGetGeometry
773       (dpy, drawable, &root, &x, &y, &width, &height, &bd, &depth)) {
774      switch (attribute) {
775      case GLX_WIDTH:
776         *value = width;
777         break;
778
779      case GLX_HEIGHT:
780         *value = height;
781         break;
782      }
783   }
784#else
785   GetDrawableAttribute(dpy, drawable, attribute, value);
786#endif
787}
788
789
790#ifndef GLX_USE_APPLEGL
791/**
792 * Query an attribute of a pbuffer.
793 */
794_X_EXPORT int
795glXQueryGLXPbufferSGIX(Display * dpy, GLXPbufferSGIX drawable,
796                       int attribute, unsigned int *value)
797{
798   return GetDrawableAttribute(dpy, drawable, attribute, value);
799}
800#endif
801
802/**
803 * Select the event mask for a drawable.
804 */
805_X_EXPORT void
806glXSelectEvent(Display * dpy, GLXDrawable drawable, unsigned long mask)
807{
808#ifdef GLX_USE_APPLEGL
809   XWindowAttributes xwattr;
810
811   if (apple_glx_pbuffer_set_event_mask(drawable, mask))
812      return;                   /*done */
813
814   /*
815    * The spec allows a window, but currently there are no valid
816    * events for a window, so do nothing.
817    */
818   if (XGetWindowAttributes(dpy, drawable, &xwattr))
819      return;                   /*done */
820   /* The drawable seems to be invalid.  Report an error. */
821
822   __glXSendError(dpy, GLXBadDrawable, drawable,
823                  X_GLXChangeDrawableAttributes, false);
824#else
825   CARD32 attribs[2];
826
827   attribs[0] = (CARD32) GLX_EVENT_MASK;
828   attribs[1] = (CARD32) mask;
829
830   ChangeDrawableAttribute(dpy, drawable, attribs, 1);
831#endif
832}
833
834
835/**
836 * Get the selected event mask for a drawable.
837 */
838_X_EXPORT void
839glXGetSelectedEvent(Display * dpy, GLXDrawable drawable, unsigned long *mask)
840{
841#ifdef GLX_USE_APPLEGL
842   XWindowAttributes xwattr;
843
844   if (apple_glx_pbuffer_get_event_mask(drawable, mask))
845      return;                   /*done */
846
847   /*
848    * The spec allows a window, but currently there are no valid
849    * events for a window, so do nothing, but set the mask to 0.
850    */
851   if (XGetWindowAttributes(dpy, drawable, &xwattr)) {
852      /* The window is valid, so set the mask to 0. */
853      *mask = 0;
854      return;                   /*done */
855   }
856   /* The drawable seems to be invalid.  Report an error. */
857
858   __glXSendError(dpy, GLXBadDrawable, drawable, X_GLXGetDrawableAttributes,
859                  true);
860#else
861   unsigned int value;
862
863
864   /* The non-sense with value is required because on LP64 platforms
865    * sizeof(unsigned int) != sizeof(unsigned long).  On little-endian
866    * we could just type-cast the pointer, but why?
867    */
868
869   GetDrawableAttribute(dpy, drawable, GLX_EVENT_MASK_SGIX, &value);
870   *mask = value;
871#endif
872}
873
874
875_X_EXPORT GLXPixmap
876glXCreatePixmap(Display * dpy, GLXFBConfig config, Pixmap pixmap,
877                const int *attrib_list)
878{
879   WARN_ONCE_GLX_1_3(dpy, __func__);
880
881#ifdef GLX_USE_APPLEGL
882   const struct glx_config *modes = (const struct glx_config *) config;
883
884   if (apple_glx_pixmap_create(dpy, modes->screen, pixmap, modes))
885      return None;
886
887   return pixmap;
888#else
889   return CreateDrawable(dpy, (struct glx_config *) config,
890                         (Drawable) pixmap, attrib_list, X_GLXCreatePixmap);
891#endif
892}
893
894
895_X_EXPORT GLXWindow
896glXCreateWindow(Display * dpy, GLXFBConfig config, Window win,
897                const int *attrib_list)
898{
899   WARN_ONCE_GLX_1_3(dpy, __func__);
900#ifdef GLX_USE_APPLEGL
901   XWindowAttributes xwattr;
902   XVisualInfo *visinfo;
903
904   (void) attrib_list;          /*unused according to GLX 1.4 */
905
906   XGetWindowAttributes(dpy, win, &xwattr);
907
908   visinfo = glXGetVisualFromFBConfig(dpy, config);
909
910   if (NULL == visinfo) {
911      __glXSendError(dpy, GLXBadFBConfig, 0, X_GLXCreateWindow, false);
912      return None;
913   }
914
915   if (visinfo->visualid != XVisualIDFromVisual(xwattr.visual)) {
916      __glXSendError(dpy, BadMatch, 0, X_GLXCreateWindow, true);
917      return None;
918   }
919
920   free(visinfo);
921
922   return win;
923#else
924   return CreateDrawable(dpy, (struct glx_config *) config,
925                         (Drawable) win, attrib_list, X_GLXCreateWindow);
926#endif
927}
928
929
930_X_EXPORT void
931glXDestroyPixmap(Display * dpy, GLXPixmap pixmap)
932{
933   WARN_ONCE_GLX_1_3(dpy, __func__);
934#ifdef GLX_USE_APPLEGL
935   if (apple_glx_pixmap_destroy(dpy, pixmap))
936      __glXSendError(dpy, GLXBadPixmap, pixmap, X_GLXDestroyPixmap, false);
937#else
938   DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap);
939#endif
940}
941
942
943_X_EXPORT void
944glXDestroyWindow(Display * dpy, GLXWindow win)
945{
946   WARN_ONCE_GLX_1_3(dpy, __func__);
947#ifndef GLX_USE_APPLEGL
948   DestroyDrawable(dpy, (GLXDrawable) win, X_GLXDestroyWindow);
949#endif
950}
951
952#ifndef GLX_USE_APPLEGL
953_X_EXPORT
954GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
955               (Display * dpy, GLXPbufferSGIX pbuf),
956               (dpy, pbuf), glXDestroyPbuffer)
957
958_X_EXPORT
959GLX_ALIAS_VOID(glXSelectEventSGIX,
960               (Display * dpy, GLXDrawable drawable,
961                unsigned long mask), (dpy, drawable, mask), glXSelectEvent)
962
963_X_EXPORT
964GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
965               (Display * dpy, GLXDrawable drawable,
966                unsigned long *mask), (dpy, drawable, mask),
967               glXGetSelectedEvent)
968#endif
969