glx_pbuffer.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
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 "glxextensions.h" 39 40#define WARN_ONCE_GLX_1_3(a, b) { \ 41 static int warned=1; \ 42 if(warned) { \ 43 warn_GLX_1_3((a), b ); \ 44 warned=0; \ 45 } \ 46 } 47 48/** 49 * Emit a warning when clients use GLX 1.3 functions on pre-1.3 systems. 50 */ 51static void 52warn_GLX_1_3(Display *dpy, const char *function_name) 53{ 54 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 55 56 if (priv->minorVersion < 3) { 57 fprintf(stderr, 58 "WARNING: Application calling GLX 1.3 function \"%s\" " 59 "when GLX 1.3 is not supported! This is an application bug!\n", 60 function_name); 61 } 62} 63 64 65/** 66 * Change a drawable's attribute. 67 * 68 * This function is used to implement \c glXSelectEvent and 69 * \c glXSelectEventSGIX. 70 * 71 * \note 72 * This function dynamically determines whether to use the SGIX_pbuffer 73 * version of the protocol or the GLX 1.3 version of the protocol. 74 * 75 * \todo 76 * This function needs to be modified to work with direct-rendering drivers. 77 */ 78static void 79ChangeDrawableAttribute(Display * dpy, GLXDrawable drawable, 80 const CARD32 * attribs, size_t num_attribs) 81{ 82 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 83 CARD32 *output; 84 CARD8 opcode; 85 86 if ((dpy == NULL) || (drawable == 0)) { 87 return; 88 } 89 90 opcode = __glXSetupForCommand(dpy); 91 if (!opcode) 92 return; 93 94 LockDisplay(dpy); 95 96 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 97 xGLXChangeDrawableAttributesReq *req; 98 99 GetReqExtra(GLXChangeDrawableAttributes, 8 + (8 * num_attribs), req); 100 output = (CARD32 *) (req + 1); 101 102 req->reqType = opcode; 103 req->glxCode = X_GLXChangeDrawableAttributes; 104 req->drawable = drawable; 105 req->numAttribs = (CARD32) num_attribs; 106 } 107 else { 108 xGLXVendorPrivateWithReplyReq *vpreq; 109 110 GetReqExtra(GLXVendorPrivateWithReply, 4 + (8 * num_attribs), vpreq); 111 output = (CARD32 *) (vpreq + 1); 112 113 vpreq->reqType = opcode; 114 vpreq->glxCode = X_GLXVendorPrivateWithReply; 115 vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX; 116 117 output[0] = (CARD32) drawable; 118 output++; 119 } 120 121 (void) memcpy(output, attribs, sizeof(CARD32) * 2 * num_attribs); 122 123 UnlockDisplay(dpy); 124 SyncHandle(); 125 126 return; 127} 128 129 130/** 131 * Destroy a pbuffer. 132 * 133 * This function is used to implement \c glXDestroyPbuffer and 134 * \c glXDestroyGLXPbufferSGIX. 135 * 136 * \note 137 * This function dynamically determines whether to use the SGIX_pbuffer 138 * version of the protocol or the GLX 1.3 version of the protocol. 139 * 140 * \todo 141 * This function needs to be modified to work with direct-rendering drivers. 142 */ 143static void 144DestroyPbuffer(Display * dpy, GLXDrawable drawable) 145{ 146 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 147 CARD8 opcode; 148 149 if ((dpy == NULL) || (drawable == 0)) { 150 return; 151 } 152 153 opcode = __glXSetupForCommand(dpy); 154 if (!opcode) 155 return; 156 157 LockDisplay(dpy); 158 159 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 160 xGLXDestroyPbufferReq *req; 161 162 GetReq(GLXDestroyPbuffer, req); 163 req->reqType = opcode; 164 req->glxCode = X_GLXDestroyPbuffer; 165 req->pbuffer = (GLXPbuffer) drawable; 166 } 167 else { 168 xGLXVendorPrivateWithReplyReq *vpreq; 169 CARD32 *data; 170 171 GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq); 172 data = (CARD32 *) (vpreq + 1); 173 174 data[0] = (CARD32) drawable; 175 176 vpreq->reqType = opcode; 177 vpreq->glxCode = X_GLXVendorPrivateWithReply; 178 vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX; 179 } 180 181 UnlockDisplay(dpy); 182 SyncHandle(); 183 184 return; 185} 186 187 188#ifdef GLX_DIRECT_RENDERING 189extern __GLXDRIdrawable *GetGLXDRIDrawable(Display * dpy, 190 GLXDrawable drawable, 191 int *const scrn_num); 192 193static GLenum 194determineTextureTarget(const int *attribs, int numAttribs) 195{ 196 GLenum target = 0; 197 int i; 198 199 for (i = 0; i < numAttribs; i++) { 200 if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) { 201 switch (attribs[2 * i + 1]) { 202 case GLX_TEXTURE_2D_EXT: 203 target = GL_TEXTURE_2D; 204 break; 205 case GLX_TEXTURE_RECTANGLE_EXT: 206 target = GL_TEXTURE_RECTANGLE_ARB; 207 break; 208 } 209 } 210 } 211 212 return target; 213} 214 215 216static GLenum 217determineTextureFormat(const int *attribs, int numAttribs) 218{ 219 int i; 220 221 for (i = 0; i < numAttribs; i++) { 222 if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT) 223 return attribs[2 * i + 1]; 224 } 225 226 return 0; 227} 228#endif 229 230/** 231 * Get a drawable's attribute. 232 * 233 * This function is used to implement \c glXGetSelectedEvent and 234 * \c glXGetSelectedEventSGIX. 235 * 236 * \note 237 * This function dynamically determines whether to use the SGIX_pbuffer 238 * version of the protocol or the GLX 1.3 version of the protocol. 239 * 240 * \todo 241 * The number of attributes returned is likely to be small, probably less than 242 * 10. Given that, this routine should try to use an array on the stack to 243 * capture the reply rather than always calling Xmalloc. 244 * 245 * \todo 246 * This function needs to be modified to work with direct-rendering drivers. 247 */ 248static int 249GetDrawableAttribute(Display * dpy, GLXDrawable drawable, 250 int attribute, unsigned int *value) 251{ 252 __GLXdisplayPrivate *priv; 253 xGLXGetDrawableAttributesReply reply; 254 CARD32 *data; 255 CARD8 opcode; 256 unsigned int length; 257 unsigned int i; 258 unsigned int num_attributes; 259 GLboolean use_glx_1_3; 260 261 if ((dpy == NULL) || (drawable == 0)) { 262 return 0; 263 } 264 265 priv = __glXInitialize(dpy); 266 use_glx_1_3 = ((priv->majorVersion > 1) || (priv->minorVersion >= 3)); 267 268 *value = 0; 269 270 271 opcode = __glXSetupForCommand(dpy); 272 if (!opcode) 273 return 0; 274 275 LockDisplay(dpy); 276 277 if (use_glx_1_3) { 278 xGLXGetDrawableAttributesReq *req; 279 280 GetReqExtra(GLXGetDrawableAttributes, 4, req); 281 req->reqType = opcode; 282 req->glxCode = X_GLXGetDrawableAttributes; 283 req->drawable = drawable; 284 } 285 else { 286 xGLXVendorPrivateWithReplyReq *vpreq; 287 288 GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq); 289 data = (CARD32 *) (vpreq + 1); 290 data[0] = (CARD32) drawable; 291 292 vpreq->reqType = opcode; 293 vpreq->glxCode = X_GLXVendorPrivateWithReply; 294 vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX; 295 } 296 297 _XReply(dpy, (xReply *) & reply, 0, False); 298 299 if (reply.type == X_Error) { 300 UnlockDisplay(dpy); 301 SyncHandle(); 302 return 0; 303 } 304 305 length = reply.length; 306 if (length) { 307 num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2; 308 data = (CARD32 *) Xmalloc(length * sizeof(CARD32)); 309 if (data == NULL) { 310 /* Throw data on the floor */ 311 _XEatData(dpy, length); 312 } 313 else { 314 _XRead(dpy, (char *) data, length * sizeof(CARD32)); 315 316 /* Search the set of returned attributes for the attribute requested by 317 * the caller. 318 */ 319 for (i = 0; i < num_attributes; i++) { 320 if (data[i * 2] == attribute) { 321 *value = data[(i * 2) + 1]; 322 break; 323 } 324 } 325 326#ifdef GLX_DIRECT_RENDERING 327 { 328 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, NULL); 329 330 if (pdraw != NULL && !pdraw->textureTarget) 331 pdraw->textureTarget = 332 determineTextureTarget((const int *) data, num_attributes); 333 if (pdraw != NULL && !pdraw->textureFormat) 334 pdraw->textureFormat = 335 determineTextureFormat((const int *) data, num_attributes); 336 } 337#endif 338 339 Xfree(data); 340 } 341 } 342 343 UnlockDisplay(dpy); 344 SyncHandle(); 345 346 return 0; 347} 348 349/** 350 * Create a non-pbuffer GLX drawable. 351 * 352 * \todo 353 * This function needs to be modified to work with direct-rendering drivers. 354 */ 355static GLXDrawable 356CreateDrawable(Display * dpy, const __GLcontextModes * fbconfig, 357 Drawable drawable, const int *attrib_list, CARD8 glxCode) 358{ 359 xGLXCreateWindowReq *req; 360 CARD32 *data; 361 unsigned int i; 362 CARD8 opcode; 363 364 i = 0; 365 if (attrib_list) { 366 while (attrib_list[i * 2] != None) 367 i++; 368 } 369 370 opcode = __glXSetupForCommand(dpy); 371 if (!opcode) 372 return None; 373 374 LockDisplay(dpy); 375 GetReqExtra(GLXCreateWindow, 8 * i, req); 376 data = (CARD32 *) (req + 1); 377 378 req->reqType = opcode; 379 req->glxCode = glxCode; 380 req->screen = (CARD32) fbconfig->screen; 381 req->fbconfig = fbconfig->fbconfigID; 382 req->window = (CARD32) drawable; 383 req->glxwindow = (GLXWindow) XAllocID(dpy); 384 req->numAttribs = (CARD32) i; 385 386 memcpy(data, attrib_list, 8 * i); 387 388 UnlockDisplay(dpy); 389 SyncHandle(); 390 391#ifdef GLX_DIRECT_RENDERING 392 do { 393 /* FIXME: Maybe delay __DRIdrawable creation until the drawable 394 * is actually bound to a context... */ 395 396 __GLXdisplayPrivate *const priv = __glXInitialize(dpy); 397 __GLXDRIdrawable *pdraw; 398 __GLXscreenConfigs *psc; 399 400 psc = &priv->screenConfigs[fbconfig->screen]; 401 if (psc->driScreen == NULL) 402 break; 403 pdraw = psc->driScreen->createDrawable(psc, drawable, 404 req->glxwindow, fbconfig); 405 if (pdraw == NULL) { 406 fprintf(stderr, "failed to create drawable\n"); 407 break; 408 } 409 410 if (__glxHashInsert(psc->drawHash, req->glxwindow, pdraw)) { 411 (*pdraw->destroyDrawable) (pdraw); 412 return None; /* FIXME: Check what we're supposed to do here... */ 413 } 414 415 pdraw->textureTarget = determineTextureTarget(attrib_list, i); 416 pdraw->textureFormat = determineTextureFormat(attrib_list, i); 417 } while (0); 418#endif 419 420 return (GLXDrawable) req->glxwindow; 421} 422 423 424/** 425 * Destroy a non-pbuffer GLX drawable. 426 * 427 * \todo 428 * This function needs to be modified to work with direct-rendering drivers. 429 */ 430static void 431DestroyDrawable(Display * dpy, GLXDrawable drawable, CARD32 glxCode) 432{ 433 xGLXDestroyPbufferReq *req; 434 CARD8 opcode; 435 436 if ((dpy == NULL) || (drawable == 0)) { 437 return; 438 } 439 440 441 opcode = __glXSetupForCommand(dpy); 442 if (!opcode) 443 return; 444 445 LockDisplay(dpy); 446 447 GetReqExtra(GLXDestroyPbuffer, 4, req); 448 req->reqType = opcode; 449 req->glxCode = glxCode; 450 req->pbuffer = (GLXPbuffer) drawable; 451 452 UnlockDisplay(dpy); 453 SyncHandle(); 454 455#ifdef GLX_DIRECT_RENDERING 456 { 457 int screen; 458 __GLXdisplayPrivate *const priv = __glXInitialize(dpy); 459 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, &screen); 460 __GLXscreenConfigs *psc = &priv->screenConfigs[screen]; 461 462 if (pdraw != NULL) { 463 (*pdraw->destroyDrawable) (pdraw); 464 __glxHashDelete(psc->drawHash, drawable); 465 } 466 } 467#endif 468 469 return; 470} 471 472 473/** 474 * Create a pbuffer. 475 * 476 * This function is used to implement \c glXCreatePbuffer and 477 * \c glXCreateGLXPbufferSGIX. 478 * 479 * \note 480 * This function dynamically determines whether to use the SGIX_pbuffer 481 * version of the protocol or the GLX 1.3 version of the protocol. 482 * 483 * \todo 484 * This function needs to be modified to work with direct-rendering drivers. 485 */ 486static GLXDrawable 487CreatePbuffer(Display * dpy, const __GLcontextModes * fbconfig, 488 unsigned int width, unsigned int height, 489 const int *attrib_list, GLboolean size_in_attribs) 490{ 491 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 492 GLXDrawable id = 0; 493 CARD32 *data; 494 CARD8 opcode; 495 unsigned int i; 496 497 i = 0; 498 if (attrib_list) { 499 while (attrib_list[i * 2]) 500 i++; 501 } 502 503 opcode = __glXSetupForCommand(dpy); 504 if (!opcode) 505 return None; 506 507 LockDisplay(dpy); 508 id = XAllocID(dpy); 509 510 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 511 xGLXCreatePbufferReq *req; 512 unsigned int extra = (size_in_attribs) ? 0 : 2; 513 514 GetReqExtra(GLXCreatePbuffer, (8 * (i + extra)), req); 515 data = (CARD32 *) (req + 1); 516 517 req->reqType = opcode; 518 req->glxCode = X_GLXCreatePbuffer; 519 req->screen = (CARD32) fbconfig->screen; 520 req->fbconfig = fbconfig->fbconfigID; 521 req->pbuffer = (GLXPbuffer) id; 522 req->numAttribs = (CARD32) (i + extra); 523 524 if (!size_in_attribs) { 525 data[(2 * i) + 0] = GLX_PBUFFER_WIDTH; 526 data[(2 * i) + 1] = width; 527 data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT; 528 data[(2 * i) + 3] = height; 529 data += 4; 530 } 531 } 532 else { 533 xGLXVendorPrivateReq *vpreq; 534 535 GetReqExtra(GLXVendorPrivate, 20 + (8 * i), vpreq); 536 data = (CARD32 *) (vpreq + 1); 537 538 vpreq->reqType = opcode; 539 vpreq->glxCode = X_GLXVendorPrivate; 540 vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX; 541 542 data[0] = (CARD32) fbconfig->screen; 543 data[1] = (CARD32) fbconfig->fbconfigID; 544 data[2] = (CARD32) id; 545 data[3] = (CARD32) width; 546 data[4] = (CARD32) height; 547 data += 5; 548 } 549 550 (void) memcpy(data, attrib_list, sizeof(CARD32) * 2 * i); 551 552 UnlockDisplay(dpy); 553 SyncHandle(); 554 555 return id; 556} 557 558 559/** 560 * Create a new pbuffer. 561 */ 562PUBLIC GLXPbufferSGIX 563glXCreateGLXPbufferSGIX(Display * dpy, GLXFBConfigSGIX config, 564 unsigned int width, unsigned int height, 565 int *attrib_list) 566{ 567 return (GLXPbufferSGIX) CreatePbuffer(dpy, (__GLcontextModes *) config, 568 width, height, 569 attrib_list, GL_FALSE); 570} 571 572 573/** 574 * Create a new pbuffer. 575 */ 576PUBLIC GLXPbuffer 577glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int *attrib_list) 578{ 579 int i, width, height; 580 581 width = 0; 582 height = 0; 583 584 WARN_ONCE_GLX_1_3(dpy, __func__); 585 586 for (i = 0; attrib_list[i * 2]; i++) { 587 switch (attrib_list[i * 2]) { 588 case GLX_PBUFFER_WIDTH: 589 width = attrib_list[i * 2 + 1]; 590 break; 591 case GLX_PBUFFER_HEIGHT: 592 height = attrib_list[i * 2 + 1]; 593 break; 594 } 595 } 596 597 return (GLXPbuffer) CreatePbuffer(dpy, (__GLcontextModes *) config, 598 width, height, attrib_list, GL_TRUE); 599} 600 601 602/** 603 * Destroy an existing pbuffer. 604 */ 605PUBLIC void 606glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf) 607{ 608 DestroyPbuffer(dpy, pbuf); 609} 610 611 612/** 613 * Query an attribute of a drawable. 614 */ 615PUBLIC void 616glXQueryDrawable(Display * dpy, GLXDrawable drawable, 617 int attribute, unsigned int *value) 618{ 619 WARN_ONCE_GLX_1_3(dpy, __func__); 620 GetDrawableAttribute(dpy, drawable, attribute, value); 621} 622 623 624/** 625 * Query an attribute of a pbuffer. 626 */ 627PUBLIC int 628glXQueryGLXPbufferSGIX(Display * dpy, GLXPbufferSGIX drawable, 629 int attribute, unsigned int *value) 630{ 631 return GetDrawableAttribute(dpy, drawable, attribute, value); 632} 633 634 635/** 636 * Select the event mask for a drawable. 637 */ 638PUBLIC void 639glXSelectEvent(Display * dpy, GLXDrawable drawable, unsigned long mask) 640{ 641 CARD32 attribs[2]; 642 643 attribs[0] = (CARD32) GLX_EVENT_MASK; 644 attribs[1] = (CARD32) mask; 645 646 ChangeDrawableAttribute(dpy, drawable, attribs, 1); 647} 648 649 650/** 651 * Get the selected event mask for a drawable. 652 */ 653PUBLIC void 654glXGetSelectedEvent(Display * dpy, GLXDrawable drawable, unsigned long *mask) 655{ 656 unsigned int value; 657 658 659 /* The non-sense with value is required because on LP64 platforms 660 * sizeof(unsigned int) != sizeof(unsigned long). On little-endian 661 * we could just type-cast the pointer, but why? 662 */ 663 664 GetDrawableAttribute(dpy, drawable, GLX_EVENT_MASK_SGIX, &value); 665 *mask = value; 666} 667 668 669PUBLIC GLXPixmap 670glXCreatePixmap(Display * dpy, GLXFBConfig config, Pixmap pixmap, 671 const int *attrib_list) 672{ 673 WARN_ONCE_GLX_1_3(dpy, __func__); 674 675 return CreateDrawable(dpy, (__GLcontextModes *) config, 676 (Drawable) pixmap, attrib_list, X_GLXCreatePixmap); 677} 678 679 680PUBLIC GLXWindow 681glXCreateWindow(Display * dpy, GLXFBConfig config, Window win, 682 const int *attrib_list) 683{ 684 WARN_ONCE_GLX_1_3(dpy, __func__); 685 686 return CreateDrawable(dpy, (__GLcontextModes *) config, 687 (Drawable) win, attrib_list, X_GLXCreateWindow); 688} 689 690 691PUBLIC void 692glXDestroyPixmap(Display * dpy, GLXPixmap pixmap) 693{ 694 WARN_ONCE_GLX_1_3(dpy, __func__); 695 696 DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap); 697} 698 699 700PUBLIC void 701glXDestroyWindow(Display * dpy, GLXWindow win) 702{ 703 WARN_ONCE_GLX_1_3(dpy, __func__); 704 705 DestroyDrawable(dpy, (GLXDrawable) win, X_GLXDestroyWindow); 706} 707 708 709PUBLIC 710GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX, 711 (Display * dpy, GLXPbufferSGIX pbuf), 712 (dpy, pbuf), glXDestroyPbuffer) 713 714PUBLIC 715GLX_ALIAS_VOID(glXSelectEventSGIX, 716 (Display * dpy, GLXDrawable drawable, 717 unsigned long mask), (dpy, drawable, mask), glXSelectEvent) 718 719PUBLIC 720GLX_ALIAS_VOID(glXGetSelectedEventSGIX, 721 (Display * dpy, GLXDrawable drawable, 722 unsigned long *mask), (dpy, drawable, mask), 723 glXGetSelectedEvent) 724 725