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