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