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