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