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