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