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