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