glx_pbuffer.c revision 97ec6076f596a3820a9b7c4b7eae18bd98c6676b
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 memcpy(data, attrib_list, 8 * i); 383 384 UnlockDisplay(dpy); 385 SyncHandle(); 386 387#ifdef GLX_DIRECT_RENDERING 388 do { 389 /* FIXME: Maybe delay __DRIdrawable creation until the drawable 390 * is actually bound to a context... */ 391 392 __GLXdisplayPrivate *const priv = __glXInitialize(dpy); 393 __GLXDRIdrawable *pdraw; 394 __GLXscreenConfigs *psc; 395 396 psc = &priv->screenConfigs[fbconfig->screen]; 397 if (psc->driScreen == NULL) 398 break; 399 pdraw = psc->driScreen->createDrawable(psc, drawable, 400 req->glxwindow, fbconfig); 401 if (pdraw == NULL) { 402 fprintf(stderr, "failed to create drawable\n"); 403 break; 404 } 405 406 if (__glxHashInsert(psc->drawHash, req->glxwindow, pdraw)) { 407 (*pdraw->destroyDrawable) (pdraw); 408 return None; /* FIXME: Check what we're supposed to do here... */ 409 } 410 411 pdraw->textureTarget = determineTextureTarget(attrib_list, i); 412 pdraw->textureFormat = determineTextureFormat(attrib_list, i); 413 } while (0); 414#endif 415 416 return (GLXDrawable) req->glxwindow; 417} 418 419 420/** 421 * Destroy a non-pbuffer GLX drawable. 422 * 423 * \todo 424 * This function needs to be modified to work with direct-rendering drivers. 425 */ 426static void 427DestroyDrawable(Display * dpy, GLXDrawable drawable, CARD32 glxCode) 428{ 429 xGLXDestroyPbufferReq *req; 430 CARD8 opcode; 431 432 if ((dpy == NULL) || (drawable == 0)) { 433 return; 434 } 435 436 437 opcode = __glXSetupForCommand(dpy); 438 if (!opcode) 439 return; 440 441 LockDisplay(dpy); 442 443 GetReqExtra(GLXDestroyPbuffer, 4, req); 444 req->reqType = opcode; 445 req->glxCode = glxCode; 446 req->pbuffer = (GLXPbuffer) drawable; 447 448 UnlockDisplay(dpy); 449 SyncHandle(); 450 451#ifdef GLX_DIRECT_RENDERING 452 { 453 int screen; 454 __GLXdisplayPrivate *const priv = __glXInitialize(dpy); 455 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, &screen); 456 __GLXscreenConfigs *psc = &priv->screenConfigs[screen]; 457 458 if (pdraw != NULL) { 459 (*pdraw->destroyDrawable) (pdraw); 460 __glxHashDelete(psc->drawHash, drawable); 461 } 462 } 463#endif 464 465 return; 466} 467 468 469/** 470 * Create a pbuffer. 471 * 472 * This function is used to implement \c glXCreatePbuffer and 473 * \c glXCreateGLXPbufferSGIX. 474 * 475 * \note 476 * This function dynamically determines whether to use the SGIX_pbuffer 477 * version of the protocol or the GLX 1.3 version of the protocol. 478 * 479 * \todo 480 * This function needs to be modified to work with direct-rendering drivers. 481 */ 482static GLXDrawable 483CreatePbuffer(Display * dpy, const __GLcontextModes * fbconfig, 484 unsigned int width, unsigned int height, 485 const int *attrib_list, GLboolean size_in_attribs) 486{ 487 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 488 GLXDrawable id = 0; 489 CARD32 *data; 490 CARD8 opcode; 491 unsigned int i; 492 493 i = 0; 494 if (attrib_list) { 495 while (attrib_list[i * 2]) 496 i++; 497 } 498 499 opcode = __glXSetupForCommand(dpy); 500 if (!opcode) 501 return None; 502 503 LockDisplay(dpy); 504 id = XAllocID(dpy); 505 506 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 507 xGLXCreatePbufferReq *req; 508 unsigned int extra = (size_in_attribs) ? 0 : 2; 509 510 GetReqExtra(GLXCreatePbuffer, (8 * (i + extra)), req); 511 data = (CARD32 *) (req + 1); 512 513 req->reqType = opcode; 514 req->glxCode = X_GLXCreatePbuffer; 515 req->screen = (CARD32) fbconfig->screen; 516 req->fbconfig = fbconfig->fbconfigID; 517 req->pbuffer = (GLXPbuffer) id; 518 req->numAttribs = (CARD32) (i + extra); 519 520 if (!size_in_attribs) { 521 data[(2 * i) + 0] = GLX_PBUFFER_WIDTH; 522 data[(2 * i) + 1] = width; 523 data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT; 524 data[(2 * i) + 3] = height; 525 data += 4; 526 } 527 } 528 else { 529 xGLXVendorPrivateReq *vpreq; 530 531 GetReqExtra(GLXVendorPrivate, 20 + (8 * i), vpreq); 532 data = (CARD32 *) (vpreq + 1); 533 534 vpreq->reqType = opcode; 535 vpreq->glxCode = X_GLXVendorPrivate; 536 vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX; 537 538 data[0] = (CARD32) fbconfig->screen; 539 data[1] = (CARD32) fbconfig->fbconfigID; 540 data[2] = (CARD32) id; 541 data[3] = (CARD32) width; 542 data[4] = (CARD32) height; 543 data += 5; 544 } 545 546 (void) memcpy(data, attrib_list, sizeof(CARD32) * 2 * i); 547 548 UnlockDisplay(dpy); 549 SyncHandle(); 550 551 return id; 552} 553 554 555/** 556 * Create a new pbuffer. 557 */ 558PUBLIC GLXPbufferSGIX 559glXCreateGLXPbufferSGIX(Display * dpy, GLXFBConfigSGIX config, 560 unsigned int width, unsigned int height, 561 int *attrib_list) 562{ 563 return (GLXPbufferSGIX) CreatePbuffer(dpy, (__GLcontextModes *) config, 564 width, height, 565 attrib_list, GL_FALSE); 566} 567 568 569/** 570 * Create a new pbuffer. 571 */ 572PUBLIC GLXPbuffer 573glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int *attrib_list) 574{ 575 int i, width, height; 576 577 width = 0; 578 height = 0; 579 580 WARN_ONCE_GLX_1_3(dpy, __func__); 581 582 for (i = 0; attrib_list[i * 2]; i++) { 583 switch (attrib_list[i * 2]) { 584 case GLX_PBUFFER_WIDTH: 585 width = attrib_list[i * 2 + 1]; 586 break; 587 case GLX_PBUFFER_HEIGHT: 588 height = attrib_list[i * 2 + 1]; 589 break; 590 } 591 } 592 593 return (GLXPbuffer) CreatePbuffer(dpy, (__GLcontextModes *) config, 594 width, height, attrib_list, GL_TRUE); 595} 596 597 598/** 599 * Destroy an existing pbuffer. 600 */ 601PUBLIC void 602glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf) 603{ 604 DestroyPbuffer(dpy, pbuf); 605} 606 607 608/** 609 * Query an attribute of a drawable. 610 */ 611PUBLIC void 612glXQueryDrawable(Display * dpy, GLXDrawable drawable, 613 int attribute, unsigned int *value) 614{ 615 WARN_ONCE_GLX_1_3(dpy, __func__); 616 GetDrawableAttribute(dpy, drawable, attribute, value); 617} 618 619 620/** 621 * Query an attribute of a pbuffer. 622 */ 623PUBLIC int 624glXQueryGLXPbufferSGIX(Display * dpy, GLXPbufferSGIX drawable, 625 int attribute, unsigned int *value) 626{ 627 return GetDrawableAttribute(dpy, drawable, attribute, value); 628} 629 630 631/** 632 * Select the event mask for a drawable. 633 */ 634PUBLIC void 635glXSelectEvent(Display * dpy, GLXDrawable drawable, unsigned long mask) 636{ 637 CARD32 attribs[2]; 638 639 attribs[0] = (CARD32) GLX_EVENT_MASK; 640 attribs[1] = (CARD32) mask; 641 642 ChangeDrawableAttribute(dpy, drawable, attribs, 1); 643} 644 645 646/** 647 * Get the selected event mask for a drawable. 648 */ 649PUBLIC void 650glXGetSelectedEvent(Display * dpy, GLXDrawable drawable, unsigned long *mask) 651{ 652 unsigned int value; 653 654 655 /* The non-sense with value is required because on LP64 platforms 656 * sizeof(unsigned int) != sizeof(unsigned long). On little-endian 657 * we could just type-cast the pointer, but why? 658 */ 659 660 GetDrawableAttribute(dpy, drawable, GLX_EVENT_MASK_SGIX, &value); 661 *mask = value; 662} 663 664 665PUBLIC GLXPixmap 666glXCreatePixmap(Display * dpy, GLXFBConfig config, Pixmap pixmap, 667 const int *attrib_list) 668{ 669 WARN_ONCE_GLX_1_3(dpy, __func__); 670 671 return CreateDrawable(dpy, (__GLcontextModes *) config, 672 (Drawable) pixmap, attrib_list, X_GLXCreatePixmap); 673} 674 675 676PUBLIC GLXWindow 677glXCreateWindow(Display * dpy, GLXFBConfig config, Window win, 678 const int *attrib_list) 679{ 680 WARN_ONCE_GLX_1_3(dpy, __func__); 681 682 return CreateDrawable(dpy, (__GLcontextModes *) config, 683 (Drawable) win, attrib_list, X_GLXCreateWindow); 684} 685 686 687PUBLIC void 688glXDestroyPixmap(Display * dpy, GLXPixmap pixmap) 689{ 690 WARN_ONCE_GLX_1_3(dpy, __func__); 691 692 DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap); 693} 694 695 696PUBLIC void 697glXDestroyWindow(Display * dpy, GLXWindow win) 698{ 699 WARN_ONCE_GLX_1_3(dpy, __func__); 700 701 DestroyDrawable(dpy, (GLXDrawable) win, X_GLXDestroyWindow); 702} 703 704 705PUBLIC 706GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX, 707 (Display * dpy, GLXPbufferSGIX pbuf), 708 (dpy, pbuf), glXDestroyPbuffer) 709 710PUBLIC 711GLX_ALIAS_VOID(glXSelectEventSGIX, 712 (Display * dpy, GLXDrawable drawable, 713 unsigned long mask), (dpy, drawable, mask), glXSelectEvent) 714 715PUBLIC 716GLX_ALIAS_VOID(glXGetSelectedEventSGIX, 717 (Display * dpy, GLXDrawable drawable, 718 unsigned long *mask), (dpy, drawable, mask), 719 glXGetSelectedEvent) 720 721