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