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