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