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