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