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