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/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 && 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 ((priv == NULL) || (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   if (priv == NULL) {
201      fprintf(stderr, "failed to create drawable\n");
202      return GL_FALSE;
203   }
204
205   psc = priv->screens[config->screen];
206   if (psc->driScreen == NULL)
207      return GL_TRUE;
208
209   pdraw = psc->driScreen->createDrawable(psc, drawable,
210					  glxdrawable, config);
211   if (pdraw == NULL) {
212      fprintf(stderr, "failed to create drawable\n");
213      return GL_FALSE;
214   }
215
216   if (__glxHashInsert(priv->drawHash, glxdrawable, pdraw)) {
217      (*pdraw->destroyDrawable) (pdraw);
218      return GL_FALSE;
219   }
220
221   pdraw->textureTarget = determineTextureTarget(attrib_list, num_attribs);
222   pdraw->textureFormat = determineTextureFormat(attrib_list, num_attribs);
223
224   return GL_TRUE;
225}
226
227static void
228DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable)
229{
230   struct glx_display *const priv = __glXInitialize(dpy);
231   __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable);
232   XID xid;
233
234   if (priv != NULL && pdraw != NULL) {
235      xid = pdraw->xDrawable;
236      (*pdraw->destroyDrawable) (pdraw);
237      __glxHashDelete(priv->drawHash, drawable);
238      if (destroy_xdrawable)
239         XFreePixmap(priv->dpy, xid);
240   }
241}
242
243#else
244
245static GLboolean
246CreateDRIDrawable(Display *dpy, const struct glx_config * fbconfig,
247		  XID drawable, XID glxdrawable,
248		  const int *attrib_list, size_t num_attribs)
249{
250    return GL_TRUE;
251}
252
253static void
254DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable)
255{
256}
257
258#endif
259
260/**
261 * Get a drawable's attribute.
262 *
263 * This function is used to implement \c glXGetSelectedEvent and
264 * \c glXGetSelectedEventSGIX.
265 *
266 * \note
267 * This function dynamically determines whether to use the SGIX_pbuffer
268 * version of the protocol or the GLX 1.3 version of the protocol.
269 *
270 * \todo
271 * The number of attributes returned is likely to be small, probably less than
272 * 10.  Given that, this routine should try to use an array on the stack to
273 * capture the reply rather than always calling Xmalloc.
274 */
275int
276__glXGetDrawableAttribute(Display * dpy, GLXDrawable drawable,
277                          int attribute, unsigned int *value)
278{
279   struct glx_display *priv;
280   xGLXGetDrawableAttributesReply reply;
281   CARD32 *data;
282   CARD8 opcode;
283   unsigned int length;
284   unsigned int i;
285   unsigned int num_attributes;
286   GLboolean use_glx_1_3;
287
288#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
289   __GLXDRIdrawable *pdraw;
290#endif
291
292   if (dpy == NULL)
293      return 0;
294
295   /* Page 38 (page 52 of the PDF) of glxencode1.3.pdf says:
296    *
297    *     "If drawable is not a valid GLX drawable, a GLXBadDrawable error is
298    *     generated."
299    */
300   if (drawable == 0) {
301      __glXSendError(dpy, GLXBadDrawable, 0, X_GLXGetDrawableAttributes, false);
302      return 0;
303   }
304
305   priv = __glXInitialize(dpy);
306   if (priv == NULL)
307      return 0;
308
309   use_glx_1_3 = ((priv->majorVersion > 1) || (priv->minorVersion >= 3));
310
311   *value = 0;
312
313
314   opcode = __glXSetupForCommand(dpy);
315   if (!opcode)
316      return 0;
317
318#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
319   pdraw = GetGLXDRIDrawable(dpy, drawable);
320
321   if (attribute == GLX_BACK_BUFFER_AGE_EXT) {
322      struct glx_context *gc = __glXGetCurrentContext();
323      struct glx_screen *psc;
324
325      /* The GLX_EXT_buffer_age spec says:
326       *
327       *   "If querying GLX_BACK_BUFFER_AGE_EXT and <draw> is not bound to
328       *   the calling thread's current context a GLXBadDrawable error is
329       *   generated."
330       */
331      if (pdraw == NULL || gc == &dummyContext || gc->currentDpy != dpy ||
332         (gc->currentDrawable != drawable &&
333         gc->currentReadable != drawable)) {
334         __glXSendError(dpy, GLXBadDrawable, drawable,
335                        X_GLXGetDrawableAttributes, false);
336         return 0;
337      }
338
339      psc = pdraw->psc;
340
341      if (psc->driScreen->getBufferAge != NULL)
342         *value = psc->driScreen->getBufferAge(pdraw);
343
344      return 0;
345   }
346#endif
347
348   LockDisplay(dpy);
349
350   if (use_glx_1_3) {
351      xGLXGetDrawableAttributesReq *req;
352
353      GetReq(GLXGetDrawableAttributes, req);
354      req->reqType = opcode;
355      req->glxCode = X_GLXGetDrawableAttributes;
356      req->drawable = drawable;
357   }
358   else {
359      xGLXVendorPrivateWithReplyReq *vpreq;
360
361      GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq);
362      data = (CARD32 *) (vpreq + 1);
363      data[0] = (CARD32) drawable;
364
365      vpreq->reqType = opcode;
366      vpreq->glxCode = X_GLXVendorPrivateWithReply;
367      vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX;
368   }
369
370   _XReply(dpy, (xReply *) & reply, 0, False);
371
372   if (reply.type == X_Error) {
373      UnlockDisplay(dpy);
374      SyncHandle();
375      return 0;
376   }
377
378   length = reply.length;
379   if (length) {
380      num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2;
381      data = malloc(length * sizeof(CARD32));
382      if (data == NULL) {
383         /* Throw data on the floor */
384         _XEatData(dpy, length);
385      }
386      else {
387         _XRead(dpy, (char *) data, length * sizeof(CARD32));
388
389         /* Search the set of returned attributes for the attribute requested by
390          * the caller.
391          */
392         for (i = 0; i < num_attributes; i++) {
393            if (data[i * 2] == attribute) {
394               *value = data[(i * 2) + 1];
395               break;
396            }
397         }
398
399#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
400         if (pdraw != NULL) {
401            if (!pdraw->textureTarget)
402               pdraw->textureTarget =
403                  determineTextureTarget((const int *) data, num_attributes);
404            if (!pdraw->textureFormat)
405               pdraw->textureFormat =
406                  determineTextureFormat((const int *) data, num_attributes);
407         }
408#endif
409
410         free(data);
411      }
412   }
413
414   UnlockDisplay(dpy);
415   SyncHandle();
416
417   return 0;
418}
419
420static void
421protocolDestroyDrawable(Display *dpy, GLXDrawable drawable, CARD32 glxCode)
422{
423   xGLXDestroyPbufferReq *req;
424   CARD8 opcode;
425
426   opcode = __glXSetupForCommand(dpy);
427   if (!opcode)
428      return;
429
430   LockDisplay(dpy);
431
432   GetReq(GLXDestroyPbuffer, req);
433   req->reqType = opcode;
434   req->glxCode = glxCode;
435   req->pbuffer = (GLXPbuffer) drawable;
436
437   UnlockDisplay(dpy);
438   SyncHandle();
439}
440
441/**
442 * Create a non-pbuffer GLX drawable.
443 */
444static GLXDrawable
445CreateDrawable(Display *dpy, struct glx_config *config,
446               Drawable drawable, const int *attrib_list, CARD8 glxCode)
447{
448   xGLXCreateWindowReq *req;
449   struct glx_drawable *glxDraw;
450   CARD32 *data;
451   unsigned int i;
452   CARD8 opcode;
453   GLXDrawable xid;
454
455   i = 0;
456   if (attrib_list) {
457      while (attrib_list[i * 2] != None)
458         i++;
459   }
460
461   opcode = __glXSetupForCommand(dpy);
462   if (!opcode)
463      return None;
464
465   glxDraw = malloc(sizeof(*glxDraw));
466   if (!glxDraw)
467      return None;
468
469   LockDisplay(dpy);
470   GetReqExtra(GLXCreateWindow, 8 * i, req);
471   data = (CARD32 *) (req + 1);
472
473   req->reqType = opcode;
474   req->glxCode = glxCode;
475   req->screen = config->screen;
476   req->fbconfig = config->fbconfigID;
477   req->window = drawable;
478   req->glxwindow = xid = XAllocID(dpy);
479   req->numAttribs = i;
480
481   if (attrib_list)
482      memcpy(data, attrib_list, 8 * i);
483
484   UnlockDisplay(dpy);
485   SyncHandle();
486
487   if (InitGLXDrawable(dpy, glxDraw, drawable, xid)) {
488      free(glxDraw);
489      return None;
490   }
491
492   if (!CreateDRIDrawable(dpy, config, drawable, xid, attrib_list, i)) {
493      if (glxCode == X_GLXCreatePixmap)
494         glxCode = X_GLXDestroyPixmap;
495      else
496         glxCode = X_GLXDestroyWindow;
497      protocolDestroyDrawable(dpy, xid, glxCode);
498      xid = None;
499   }
500
501   return xid;
502}
503
504
505/**
506 * Destroy a non-pbuffer GLX drawable.
507 */
508static void
509DestroyDrawable(Display * dpy, GLXDrawable drawable, CARD32 glxCode)
510{
511   if ((dpy == NULL) || (drawable == 0)) {
512      return;
513   }
514
515   protocolDestroyDrawable(dpy, drawable, glxCode);
516
517   DestroyGLXDrawable(dpy, drawable);
518   DestroyDRIDrawable(dpy, drawable, GL_FALSE);
519
520   return;
521}
522
523
524/**
525 * Create a pbuffer.
526 *
527 * This function is used to implement \c glXCreatePbuffer and
528 * \c glXCreateGLXPbufferSGIX.
529 *
530 * \note
531 * This function dynamically determines whether to use the SGIX_pbuffer
532 * version of the protocol or the GLX 1.3 version of the protocol.
533 */
534static GLXDrawable
535CreatePbuffer(Display * dpy, struct glx_config *config,
536              unsigned int width, unsigned int height,
537              const int *attrib_list, GLboolean size_in_attribs)
538{
539   struct glx_display *priv = __glXInitialize(dpy);
540   GLXDrawable id = 0;
541   CARD32 *data;
542   CARD8 opcode;
543   unsigned int i;
544   Pixmap pixmap;
545   GLboolean glx_1_3 = GL_FALSE;
546
547   if (priv == NULL)
548      return None;
549
550   i = 0;
551   if (attrib_list) {
552      while (attrib_list[i * 2])
553         i++;
554   }
555
556   opcode = __glXSetupForCommand(dpy);
557   if (!opcode)
558      return None;
559
560   LockDisplay(dpy);
561   id = XAllocID(dpy);
562
563   if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
564      xGLXCreatePbufferReq *req;
565      unsigned int extra = (size_in_attribs) ? 0 : 2;
566
567      glx_1_3 = GL_TRUE;
568
569      GetReqExtra(GLXCreatePbuffer, (8 * (i + extra)), req);
570      data = (CARD32 *) (req + 1);
571
572      req->reqType = opcode;
573      req->glxCode = X_GLXCreatePbuffer;
574      req->screen = config->screen;
575      req->fbconfig = config->fbconfigID;
576      req->pbuffer = id;
577      req->numAttribs = i + extra;
578
579      if (!size_in_attribs) {
580         data[(2 * i) + 0] = GLX_PBUFFER_WIDTH;
581         data[(2 * i) + 1] = width;
582         data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT;
583         data[(2 * i) + 3] = height;
584         data += 4;
585      }
586   }
587   else {
588      xGLXVendorPrivateReq *vpreq;
589
590      GetReqExtra(GLXVendorPrivate, 20 + (8 * i), vpreq);
591      data = (CARD32 *) (vpreq + 1);
592
593      vpreq->reqType = opcode;
594      vpreq->glxCode = X_GLXVendorPrivate;
595      vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX;
596
597      data[0] = config->screen;
598      data[1] = config->fbconfigID;
599      data[2] = id;
600      data[3] = width;
601      data[4] = height;
602      data += 5;
603   }
604
605   (void) memcpy(data, attrib_list, sizeof(CARD32) * 2 * i);
606
607   UnlockDisplay(dpy);
608   SyncHandle();
609
610   pixmap = XCreatePixmap(dpy, RootWindow(dpy, config->screen),
611			  width, height, config->rgbBits);
612
613   if (!CreateDRIDrawable(dpy, config, pixmap, id, attrib_list, i)) {
614      CARD32 o = glx_1_3 ? X_GLXDestroyPbuffer : X_GLXvop_DestroyGLXPbufferSGIX;
615      XFreePixmap(dpy, pixmap);
616      protocolDestroyDrawable(dpy, id, o);
617      id = None;
618   }
619
620   return id;
621}
622
623/**
624 * Destroy a pbuffer.
625 *
626 * This function is used to implement \c glXDestroyPbuffer and
627 * \c glXDestroyGLXPbufferSGIX.
628 *
629 * \note
630 * This function dynamically determines whether to use the SGIX_pbuffer
631 * version of the protocol or the GLX 1.3 version of the protocol.
632 */
633static void
634DestroyPbuffer(Display * dpy, GLXDrawable drawable)
635{
636   struct glx_display *priv = __glXInitialize(dpy);
637   CARD8 opcode;
638
639   if ((priv == NULL) || (dpy == NULL) || (drawable == 0)) {
640      return;
641   }
642
643   opcode = __glXSetupForCommand(dpy);
644   if (!opcode)
645      return;
646
647   LockDisplay(dpy);
648
649   if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
650      xGLXDestroyPbufferReq *req;
651
652      GetReq(GLXDestroyPbuffer, req);
653      req->reqType = opcode;
654      req->glxCode = X_GLXDestroyPbuffer;
655      req->pbuffer = (GLXPbuffer) drawable;
656   }
657   else {
658      xGLXVendorPrivateWithReplyReq *vpreq;
659      CARD32 *data;
660
661      GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq);
662      data = (CARD32 *) (vpreq + 1);
663
664      data[0] = (CARD32) drawable;
665
666      vpreq->reqType = opcode;
667      vpreq->glxCode = X_GLXVendorPrivateWithReply;
668      vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX;
669   }
670
671   UnlockDisplay(dpy);
672   SyncHandle();
673
674   DestroyDRIDrawable(dpy, drawable, GL_TRUE);
675
676   return;
677}
678
679/**
680 * Create a new pbuffer.
681 */
682_GLX_PUBLIC GLXPbufferSGIX
683glXCreateGLXPbufferSGIX(Display * dpy, GLXFBConfigSGIX config,
684                        unsigned int width, unsigned int height,
685                        int *attrib_list)
686{
687   return (GLXPbufferSGIX) CreatePbuffer(dpy, (struct glx_config *) config,
688                                         width, height,
689                                         attrib_list, GL_FALSE);
690}
691
692#endif /* GLX_USE_APPLEGL */
693
694/**
695 * Create a new pbuffer.
696 */
697_GLX_PUBLIC GLXPbuffer
698glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int *attrib_list)
699{
700   int i, width, height;
701#ifdef GLX_USE_APPLEGL
702   GLXPbuffer result;
703   int errorcode;
704#endif
705
706   width = 0;
707   height = 0;
708
709   WARN_ONCE_GLX_1_3(dpy, __func__);
710
711#ifdef GLX_USE_APPLEGL
712   for (i = 0; attrib_list[i]; ++i) {
713      switch (attrib_list[i]) {
714      case GLX_PBUFFER_WIDTH:
715         width = attrib_list[i + 1];
716         ++i;
717         break;
718
719      case GLX_PBUFFER_HEIGHT:
720         height = attrib_list[i + 1];
721         ++i;
722         break;
723
724      case GLX_LARGEST_PBUFFER:
725         /* This is a hint we should probably handle, but how? */
726         ++i;
727         break;
728
729      case GLX_PRESERVED_CONTENTS:
730         /* The contents are always preserved with AppleSGLX with CGL. */
731         ++i;
732         break;
733
734      default:
735         return None;
736      }
737   }
738
739   if (apple_glx_pbuffer_create(dpy, config, width, height, &errorcode,
740                                &result)) {
741      /*
742       * apple_glx_pbuffer_create only sets the errorcode to core X11
743       * errors.
744       */
745      __glXSendError(dpy, errorcode, 0, X_GLXCreatePbuffer, true);
746
747      return None;
748   }
749
750   return result;
751#else
752   for (i = 0; attrib_list[i * 2]; i++) {
753      switch (attrib_list[i * 2]) {
754      case GLX_PBUFFER_WIDTH:
755         width = attrib_list[i * 2 + 1];
756         break;
757      case GLX_PBUFFER_HEIGHT:
758         height = attrib_list[i * 2 + 1];
759         break;
760      }
761   }
762
763   return (GLXPbuffer) CreatePbuffer(dpy, (struct glx_config *) config,
764                                     width, height, attrib_list, GL_TRUE);
765#endif
766}
767
768
769/**
770 * Destroy an existing pbuffer.
771 */
772_GLX_PUBLIC void
773glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf)
774{
775#ifdef GLX_USE_APPLEGL
776   if (apple_glx_pbuffer_destroy(dpy, pbuf)) {
777      __glXSendError(dpy, GLXBadPbuffer, pbuf, X_GLXDestroyPbuffer, false);
778   }
779#else
780   DestroyPbuffer(dpy, pbuf);
781#endif
782}
783
784
785/**
786 * Query an attribute of a drawable.
787 */
788_GLX_PUBLIC void
789glXQueryDrawable(Display * dpy, GLXDrawable drawable,
790                 int attribute, unsigned int *value)
791{
792   WARN_ONCE_GLX_1_3(dpy, __func__);
793#ifdef GLX_USE_APPLEGL
794   Window root;
795   int x, y;
796   unsigned int width, height, bd, depth;
797
798   if (apple_glx_pixmap_query(drawable, attribute, value))
799      return;                   /*done */
800
801   if (apple_glx_pbuffer_query(drawable, attribute, value))
802      return;                   /*done */
803
804   /*
805    * The OpenGL spec states that we should report GLXBadDrawable if
806    * the drawable is invalid, however doing so would require that we
807    * use XSetErrorHandler(), which is known to not be thread safe.
808    * If we use a round-trip call to validate the drawable, there could
809    * be a race, so instead we just opt in favor of letting the
810    * XGetGeometry request fail with a GetGeometry request X error
811    * rather than GLXBadDrawable, in what is hoped to be a rare
812    * case of an invalid drawable.  In practice most and possibly all
813    * X11 apps using GLX shouldn't notice a difference.
814    */
815   if (XGetGeometry
816       (dpy, drawable, &root, &x, &y, &width, &height, &bd, &depth)) {
817      switch (attribute) {
818      case GLX_WIDTH:
819         *value = width;
820         break;
821
822      case GLX_HEIGHT:
823         *value = height;
824         break;
825      }
826   }
827#else
828   __glXGetDrawableAttribute(dpy, drawable, attribute, value);
829#endif
830}
831
832
833#ifndef GLX_USE_APPLEGL
834/**
835 * Query an attribute of a pbuffer.
836 */
837_GLX_PUBLIC int
838glXQueryGLXPbufferSGIX(Display * dpy, GLXPbufferSGIX drawable,
839                       int attribute, unsigned int *value)
840{
841   return __glXGetDrawableAttribute(dpy, drawable, attribute, value);
842}
843#endif
844
845/**
846 * Select the event mask for a drawable.
847 */
848_GLX_PUBLIC void
849glXSelectEvent(Display * dpy, GLXDrawable drawable, unsigned long mask)
850{
851#ifdef GLX_USE_APPLEGL
852   XWindowAttributes xwattr;
853
854   if (apple_glx_pbuffer_set_event_mask(drawable, mask))
855      return;                   /*done */
856
857   /*
858    * The spec allows a window, but currently there are no valid
859    * events for a window, so do nothing.
860    */
861   if (XGetWindowAttributes(dpy, drawable, &xwattr))
862      return;                   /*done */
863   /* The drawable seems to be invalid.  Report an error. */
864
865   __glXSendError(dpy, GLXBadDrawable, drawable,
866                  X_GLXChangeDrawableAttributes, false);
867#else
868   CARD32 attribs[2];
869
870   attribs[0] = (CARD32) GLX_EVENT_MASK;
871   attribs[1] = (CARD32) mask;
872
873   ChangeDrawableAttribute(dpy, drawable, attribs, 1);
874#endif
875}
876
877
878/**
879 * Get the selected event mask for a drawable.
880 */
881_GLX_PUBLIC void
882glXGetSelectedEvent(Display * dpy, GLXDrawable drawable, unsigned long *mask)
883{
884#ifdef GLX_USE_APPLEGL
885   XWindowAttributes xwattr;
886
887   if (apple_glx_pbuffer_get_event_mask(drawable, mask))
888      return;                   /*done */
889
890   /*
891    * The spec allows a window, but currently there are no valid
892    * events for a window, so do nothing, but set the mask to 0.
893    */
894   if (XGetWindowAttributes(dpy, drawable, &xwattr)) {
895      /* The window is valid, so set the mask to 0. */
896      *mask = 0;
897      return;                   /*done */
898   }
899   /* The drawable seems to be invalid.  Report an error. */
900
901   __glXSendError(dpy, GLXBadDrawable, drawable, X_GLXGetDrawableAttributes,
902                  true);
903#else
904   unsigned int value = 0;
905
906
907   /* The non-sense with value is required because on LP64 platforms
908    * sizeof(unsigned int) != sizeof(unsigned long).  On little-endian
909    * we could just type-cast the pointer, but why?
910    */
911
912   __glXGetDrawableAttribute(dpy, drawable, GLX_EVENT_MASK_SGIX, &value);
913   *mask = value;
914#endif
915}
916
917
918_GLX_PUBLIC GLXPixmap
919glXCreatePixmap(Display * dpy, GLXFBConfig config, Pixmap pixmap,
920                const int *attrib_list)
921{
922   WARN_ONCE_GLX_1_3(dpy, __func__);
923
924#ifdef GLX_USE_APPLEGL
925   const struct glx_config *modes = (const struct glx_config *) config;
926
927   if (apple_glx_pixmap_create(dpy, modes->screen, pixmap, modes))
928      return None;
929
930   return pixmap;
931#else
932   return CreateDrawable(dpy, (struct glx_config *) config,
933                         (Drawable) pixmap, attrib_list, X_GLXCreatePixmap);
934#endif
935}
936
937
938_GLX_PUBLIC GLXWindow
939glXCreateWindow(Display * dpy, GLXFBConfig config, Window win,
940                const int *attrib_list)
941{
942   WARN_ONCE_GLX_1_3(dpy, __func__);
943#ifdef GLX_USE_APPLEGL
944   XWindowAttributes xwattr;
945   XVisualInfo *visinfo;
946
947   (void) attrib_list;          /*unused according to GLX 1.4 */
948
949   XGetWindowAttributes(dpy, win, &xwattr);
950
951   visinfo = glXGetVisualFromFBConfig(dpy, config);
952
953   if (NULL == visinfo) {
954      __glXSendError(dpy, GLXBadFBConfig, 0, X_GLXCreateWindow, false);
955      return None;
956   }
957
958   if (visinfo->visualid != XVisualIDFromVisual(xwattr.visual)) {
959      __glXSendError(dpy, BadMatch, 0, X_GLXCreateWindow, true);
960      return None;
961   }
962
963   free(visinfo);
964
965   return win;
966#else
967   return CreateDrawable(dpy, (struct glx_config *) config,
968                         (Drawable) win, attrib_list, X_GLXCreateWindow);
969#endif
970}
971
972
973_GLX_PUBLIC void
974glXDestroyPixmap(Display * dpy, GLXPixmap pixmap)
975{
976   WARN_ONCE_GLX_1_3(dpy, __func__);
977#ifdef GLX_USE_APPLEGL
978   if (apple_glx_pixmap_destroy(dpy, pixmap))
979      __glXSendError(dpy, GLXBadPixmap, pixmap, X_GLXDestroyPixmap, false);
980#else
981   DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap);
982#endif
983}
984
985
986_GLX_PUBLIC void
987glXDestroyWindow(Display * dpy, GLXWindow win)
988{
989   WARN_ONCE_GLX_1_3(dpy, __func__);
990#ifndef GLX_USE_APPLEGL
991   DestroyDrawable(dpy, (GLXDrawable) win, X_GLXDestroyWindow);
992#endif
993}
994
995_GLX_PUBLIC
996GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
997               (Display * dpy, GLXPbufferSGIX pbuf),
998               (dpy, pbuf), glXDestroyPbuffer)
999
1000_GLX_PUBLIC
1001GLX_ALIAS_VOID(glXSelectEventSGIX,
1002               (Display * dpy, GLXDrawable drawable,
1003                unsigned long mask), (dpy, drawable, mask), glXSelectEvent)
1004
1005_GLX_PUBLIC
1006GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
1007               (Display * dpy, GLXDrawable drawable,
1008                unsigned long *mask), (dpy, drawable, mask),
1009               glXGetSelectedEvent)
1010