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