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