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