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