xm_api.c revision 61e843ff4bf9b9e8c4a7a8a485cee852a4f1dd86
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file xm_api.c 27 * 28 * All the XMesa* API functions. 29 * 30 * 31 * NOTES: 32 * 33 * The window coordinate system origin (0,0) is in the lower-left corner 34 * of the window. X11's window coordinate origin is in the upper-left 35 * corner of the window. Therefore, most drawing functions in this 36 * file have to flip Y coordinates. 37 * 38 * Define USE_XSHM in the Makefile with -DUSE_XSHM if you want to compile 39 * in support for the MIT Shared Memory extension. If enabled, when you 40 * use an Ximage for the back buffer in double buffered mode, the "swap" 41 * operation will be faster. You must also link with -lXext. 42 * 43 * Byte swapping: If the Mesa host and the X display use a different 44 * byte order then there's some trickiness to be aware of when using 45 * XImages. The byte ordering used for the XImage is that of the X 46 * display, not the Mesa host. 47 * The color-to-pixel encoding for True/DirectColor must be done 48 * according to the display's visual red_mask, green_mask, and blue_mask. 49 * If XPutPixel is used to put a pixel into an XImage then XPutPixel will 50 * do byte swapping if needed. If one wants to directly "poke" the pixel 51 * into the XImage's buffer then the pixel must be byte swapped first. 52 * 53 */ 54 55#ifdef __CYGWIN__ 56#undef WIN32 57#undef __WIN32__ 58#endif 59 60#include "xm_api.h" 61#include "main/context.h" 62#include "main/framebuffer.h" 63 64#include "state_tracker/st_public.h" 65#include "state_tracker/st_context.h" 66#include "pipe/p_defines.h" 67#include "pipe/p_screen.h" 68#include "pipe/p_winsys.h" 69#include "pipe/p_context.h" 70 71#include "xm_winsys.h" 72#include <GL/glx.h> 73 74/** 75 * Global X driver lock 76 */ 77pipe_mutex _xmesa_lock; 78 79 80 81/**********************************************************************/ 82/***** X Utility Functions *****/ 83/**********************************************************************/ 84 85 86/** 87 * Return the host's byte order as LSBFirst or MSBFirst ala X. 88 */ 89static int host_byte_order( void ) 90{ 91 int i = 1; 92 char *cptr = (char *) &i; 93 return (*cptr==1) ? LSBFirst : MSBFirst; 94} 95 96 97/** 98 * Check if the X Shared Memory extension is available. 99 * Return: 0 = not available 100 * 1 = shared XImage support available 101 * 2 = shared Pixmap support available also 102 */ 103int xmesa_check_for_xshm( Display *display ) 104{ 105#if defined(USE_XSHM) 106 int major, minor, ignore; 107 Bool pixmaps; 108 109 if (getenv("SP_NO_RAST")) 110 return 0; 111 112 if (getenv("MESA_NOSHM")) { 113 return 0; 114 } 115 116 if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) { 117 if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) { 118 return (pixmaps==True) ? 2 : 1; 119 } 120 else { 121 return 0; 122 } 123 } 124 else { 125 return 0; 126 } 127#else 128 /* No XSHM support */ 129 return 0; 130#endif 131} 132 133 134/** 135 * Return the true number of bits per pixel for XImages. 136 * For example, if we request a 24-bit deep visual we may actually need/get 137 * 32bpp XImages. This function returns the appropriate bpp. 138 * Input: dpy - the X display 139 * visinfo - desribes the visual to be used for XImages 140 * Return: true number of bits per pixel for XImages 141 */ 142static int 143bits_per_pixel( XMesaVisual xmv ) 144{ 145 Display *dpy = xmv->display; 146 XVisualInfo * visinfo = xmv->visinfo; 147 XImage *img; 148 int bitsPerPixel; 149 /* Create a temporary XImage */ 150 img = XCreateImage( dpy, visinfo->visual, visinfo->depth, 151 ZPixmap, 0, /*format, offset*/ 152 (char*) MALLOC(8), /*data*/ 153 1, 1, /*width, height*/ 154 32, /*bitmap_pad*/ 155 0 /*bytes_per_line*/ 156 ); 157 assert(img); 158 /* grab the bits/pixel value */ 159 bitsPerPixel = img->bits_per_pixel; 160 /* free the XImage */ 161 _mesa_free( img->data ); 162 img->data = NULL; 163 XDestroyImage( img ); 164 return bitsPerPixel; 165} 166 167 168 169/* 170 * Determine if a given X window ID is valid (window exists). 171 * Do this by calling XGetWindowAttributes() for the window and 172 * checking if we catch an X error. 173 * Input: dpy - the display 174 * win - the window to check for existance 175 * Return: GL_TRUE - window exists 176 * GL_FALSE - window doesn't exist 177 */ 178static GLboolean WindowExistsFlag; 179 180static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr ) 181{ 182 (void) dpy; 183 if (xerr->error_code == BadWindow) { 184 WindowExistsFlag = GL_FALSE; 185 } 186 return 0; 187} 188 189static GLboolean window_exists( Display *dpy, Window win ) 190{ 191 XWindowAttributes wa; 192 int (*old_handler)( Display*, XErrorEvent* ); 193 WindowExistsFlag = GL_TRUE; 194 old_handler = XSetErrorHandler(window_exists_err_handler); 195 XGetWindowAttributes( dpy, win, &wa ); /* dummy request */ 196 XSetErrorHandler(old_handler); 197 return WindowExistsFlag; 198} 199 200static Status 201get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height ) 202{ 203 Window root; 204 Status stat; 205 int xpos, ypos; 206 unsigned int w, h, bw, depth; 207 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); 208 *width = w; 209 *height = h; 210 return stat; 211} 212 213 214/** 215 * Return the size of the window (or pixmap) that corresponds to the 216 * given XMesaBuffer. 217 * \param width returns width in pixels 218 * \param height returns height in pixels 219 */ 220static void 221xmesa_get_window_size(Display *dpy, XMesaBuffer b, 222 GLuint *width, GLuint *height) 223{ 224 Status stat; 225 226 pipe_mutex_lock(_xmesa_lock); 227 XSync(b->xm_visual->display, 0); /* added for Chromium */ 228 stat = get_drawable_size(dpy, b->drawable, width, height); 229 pipe_mutex_unlock(_xmesa_lock); 230 231 if (!stat) { 232 /* probably querying a window that's recently been destroyed */ 233 _mesa_warning(NULL, "XGetGeometry failed!\n"); 234 *width = *height = 1; 235 } 236} 237 238#define GET_REDMASK(__v) __v->mesa_visual.redMask 239#define GET_GREENMASK(__v) __v->mesa_visual.greenMask 240#define GET_BLUEMASK(__v) __v->mesa_visual.blueMask 241 242 243/** 244 * Choose the pixel format for the given visual. 245 * This will tell the gallium driver how to pack pixel data into 246 * drawing surfaces. 247 */ 248static GLuint 249choose_pixel_format(XMesaVisual v) 250{ 251 boolean native_byte_order = (host_byte_order() == 252 ImageByteOrder(v->display)); 253 254 if ( GET_REDMASK(v) == 0x0000ff 255 && GET_GREENMASK(v) == 0x00ff00 256 && GET_BLUEMASK(v) == 0xff0000 257 && v->BitsPerPixel == 32) { 258 if (native_byte_order) { 259 /* no byteswapping needed */ 260 return 0 /* PIXEL_FORMAT_U_A8_B8_G8_R8 */; 261 } 262 else { 263 return PIPE_FORMAT_R8G8B8A8_UNORM; 264 } 265 } 266 else if ( GET_REDMASK(v) == 0xff0000 267 && GET_GREENMASK(v) == 0x00ff00 268 && GET_BLUEMASK(v) == 0x0000ff 269 && v->BitsPerPixel == 32) { 270 if (native_byte_order) { 271 /* no byteswapping needed */ 272 return PIPE_FORMAT_A8R8G8B8_UNORM; 273 } 274 else { 275 return PIPE_FORMAT_B8G8R8A8_UNORM; 276 } 277 } 278 else if ( GET_REDMASK(v) == 0xf800 279 && GET_GREENMASK(v) == 0x07e0 280 && GET_BLUEMASK(v) == 0x001f 281 && native_byte_order 282 && v->BitsPerPixel == 16) { 283 /* 5-6-5 RGB */ 284 return PIPE_FORMAT_R5G6B5_UNORM; 285 } 286 287 assert(0); 288 return 0; 289} 290 291 292 293/**********************************************************************/ 294/***** Linked list of XMesaBuffers *****/ 295/**********************************************************************/ 296 297XMesaBuffer XMesaBufferList = NULL; 298 299 300/** 301 * Allocate a new XMesaBuffer object which corresponds to the given drawable. 302 * Note that XMesaBuffer is derived from GLframebuffer. 303 * The new XMesaBuffer will not have any size (Width=Height=0). 304 * 305 * \param d the corresponding X drawable (window or pixmap) 306 * \param type either WINDOW, PIXMAP or PBUFFER, describing d 307 * \param vis the buffer's visual 308 * \param cmap the window's colormap, if known. 309 * \return new XMesaBuffer or NULL if any problem 310 */ 311static XMesaBuffer 312create_xmesa_buffer(Drawable d, BufferType type, 313 XMesaVisual vis, Colormap cmap) 314{ 315 XMesaBuffer b; 316 GLframebuffer *fb; 317 enum pipe_format colorFormat, depthFormat, stencilFormat; 318 uint width, height; 319 320 ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER); 321 322 b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer); 323 if (!b) 324 return NULL; 325 326 b->drawable = d; 327 328 b->xm_visual = vis; 329 b->type = type; 330 b->cmap = cmap; 331 332 /* determine PIPE_FORMATs for buffers */ 333 colorFormat = choose_pixel_format(vis); 334 335 if (vis->mesa_visual.depthBits == 0) 336 depthFormat = PIPE_FORMAT_NONE; 337#ifdef GALLIUM_CELL /* XXX temporary for Cell! */ 338 else 339 depthFormat = PIPE_FORMAT_S8Z24_UNORM; 340#else 341 else if (vis->mesa_visual.depthBits <= 16) 342 depthFormat = PIPE_FORMAT_Z16_UNORM; 343 else if (vis->mesa_visual.depthBits <= 24) 344 depthFormat = PIPE_FORMAT_S8Z24_UNORM; 345 else 346 depthFormat = PIPE_FORMAT_Z32_UNORM; 347#endif 348 349 if (vis->mesa_visual.stencilBits == 8) { 350 if (depthFormat == PIPE_FORMAT_S8Z24_UNORM) 351 stencilFormat = depthFormat; 352 else 353 stencilFormat = PIPE_FORMAT_S8_UNORM; 354 } 355 else { 356 /* no stencil */ 357 stencilFormat = PIPE_FORMAT_NONE; 358 if (depthFormat == PIPE_FORMAT_S8Z24_UNORM) { 359 /* use 24-bit Z, undefined stencil channel */ 360 depthFormat = PIPE_FORMAT_X8Z24_UNORM; 361 } 362 } 363 364 365 get_drawable_size(vis->display, d, &width, &height); 366 367 /* 368 * Create framebuffer, but we'll plug in our own renderbuffers below. 369 */ 370 b->stfb = st_create_framebuffer(&vis->mesa_visual, 371 colorFormat, depthFormat, stencilFormat, 372 width, height, 373 (void *) b); 374 fb = &b->stfb->Base; 375 376 /* 377 * Create scratch XImage for xmesa_display_surface() 378 */ 379 b->tempImage = XCreateImage(vis->display, 380 vis->visinfo->visual, 381 vis->visinfo->depth, 382 ZPixmap, 0, /* format, offset */ 383 NULL, /* data */ 384 0, 0, /* size */ 385 32, /* bitmap_pad */ 386 0); /* bytes_per_line */ 387 388 /* GLX_EXT_texture_from_pixmap */ 389 b->TextureTarget = 0; 390 b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT; 391 b->TextureMipmap = 0; 392 393 /* insert buffer into linked list */ 394 b->Next = XMesaBufferList; 395 XMesaBufferList = b; 396 397 return b; 398} 399 400 401/** 402 * Find an XMesaBuffer by matching X display and colormap but NOT matching 403 * the notThis buffer. 404 */ 405XMesaBuffer 406xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis) 407{ 408 XMesaBuffer b; 409 for (b = XMesaBufferList; b; b = b->Next) { 410 if (b->xm_visual->display == dpy && 411 b->cmap == cmap && 412 b != notThis) { 413 return b; 414 } 415 } 416 return NULL; 417} 418 419 420/** 421 * Remove buffer from linked list, delete if no longer referenced. 422 */ 423static void 424xmesa_free_buffer(XMesaBuffer buffer) 425{ 426 XMesaBuffer prev = NULL, b; 427 428 for (b = XMesaBufferList; b; b = b->Next) { 429 if (b == buffer) { 430 struct gl_framebuffer *fb = &buffer->stfb->Base; 431 432 /* unlink buffer from list */ 433 if (prev) 434 prev->Next = buffer->Next; 435 else 436 XMesaBufferList = buffer->Next; 437 438 /* mark as delete pending */ 439 fb->DeletePending = GL_TRUE; 440 441 /* Since the X window for the XMesaBuffer is going away, we don't 442 * want to dereference this pointer in the future. 443 */ 444 b->drawable = 0; 445 446 buffer->tempImage->data = NULL; 447 XDestroyImage(buffer->tempImage); 448 449 /* Unreference. If count = zero we'll really delete the buffer */ 450 _mesa_unreference_framebuffer(&fb); 451 452 XFreeGC(b->xm_visual->display, b->gc); 453 454 free(buffer); 455 456 return; 457 } 458 /* continue search */ 459 prev = b; 460 } 461 /* buffer not found in XMesaBufferList */ 462 _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n"); 463} 464 465 466 467/**********************************************************************/ 468/***** Misc Private Functions *****/ 469/**********************************************************************/ 470 471 472/** 473 * When a context is bound for the first time, we can finally finish 474 * initializing the context's visual and buffer information. 475 * \param v the XMesaVisual to initialize 476 * \param b the XMesaBuffer to initialize (may be NULL) 477 * \param rgb_flag TRUE = RGBA mode, FALSE = color index mode 478 * \param window the window/pixmap we're rendering into 479 * \param cmap the colormap associated with the window/pixmap 480 * \return GL_TRUE=success, GL_FALSE=failure 481 */ 482static GLboolean 483initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b, 484 GLboolean rgb_flag, Drawable window, 485 Colormap cmap) 486{ 487 ASSERT(!b || b->xm_visual == v); 488 489 /* Save true bits/pixel */ 490 v->BitsPerPixel = bits_per_pixel(v); 491 assert(v->BitsPerPixel > 0); 492 493 if (rgb_flag == GL_FALSE) { 494 /* COLOR-INDEXED WINDOW: not supported*/ 495 return GL_FALSE; 496 } 497 else { 498 /* RGB WINDOW: 499 * We support RGB rendering into almost any kind of visual. 500 */ 501 const int xclass = v->mesa_visual.visualType; 502 if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) { 503 _mesa_warning(NULL, 504 "XMesa: RGB mode rendering not supported in given visual.\n"); 505 return GL_FALSE; 506 } 507 v->mesa_visual.indexBits = 0; 508 509 if (v->BitsPerPixel == 32) { 510 /* We use XImages for all front/back buffers. If an X Window or 511 * X Pixmap is 32bpp, there's no guarantee that the alpha channel 512 * will be preserved. For XImages we're in luck. 513 */ 514 v->mesa_visual.alphaBits = 8; 515 } 516 } 517 518 /* 519 * If MESA_INFO env var is set print out some debugging info 520 * which can help Brian figure out what's going on when a user 521 * reports bugs. 522 */ 523 if (_mesa_getenv("MESA_INFO")) { 524 _mesa_printf("X/Mesa visual = %p\n", (void *) v); 525 _mesa_printf("X/Mesa level = %d\n", v->mesa_visual.level); 526 _mesa_printf("X/Mesa depth = %d\n", v->visinfo->depth); 527 _mesa_printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel); 528 } 529 530 if (b && window) { 531 /* these should have been set in create_xmesa_buffer */ 532 ASSERT(b->drawable == window); 533 534 /* Setup for single/double buffering */ 535 if (v->mesa_visual.doubleBufferMode) { 536 /* Double buffered */ 537 b->shm = xmesa_check_for_xshm( v->display ); 538 } 539 540 /* X11 graphics context */ 541 b->gc = XCreateGC( v->display, window, 0, NULL ); 542 XSetFunction( v->display, b->gc, GXcopy ); 543 } 544 545 return GL_TRUE; 546} 547 548 549 550#define NUM_VISUAL_TYPES 6 551 552/** 553 * Convert an X visual type to a GLX visual type. 554 * 555 * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) 556 * to be converted. 557 * \return If \c visualType is a valid X visual type, a GLX visual type will 558 * be returned. Otherwise \c GLX_NONE will be returned. 559 * 560 * \note 561 * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the 562 * DRI CVS tree. 563 */ 564static GLint 565xmesa_convert_from_x_visual_type( int visualType ) 566{ 567 static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { 568 GLX_STATIC_GRAY, GLX_GRAY_SCALE, 569 GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, 570 GLX_TRUE_COLOR, GLX_DIRECT_COLOR 571 }; 572 573 return ( (unsigned) visualType < NUM_VISUAL_TYPES ) 574 ? glx_visual_types[ visualType ] : GLX_NONE; 575} 576 577 578/**********************************************************************/ 579/***** Public Functions *****/ 580/**********************************************************************/ 581 582 583/* 584 * Create a new X/Mesa visual. 585 * Input: display - X11 display 586 * visinfo - an XVisualInfo pointer 587 * rgb_flag - GL_TRUE = RGB mode, 588 * GL_FALSE = color index mode 589 * alpha_flag - alpha buffer requested? 590 * db_flag - GL_TRUE = double-buffered, 591 * GL_FALSE = single buffered 592 * stereo_flag - stereo visual? 593 * ximage_flag - GL_TRUE = use an XImage for back buffer, 594 * GL_FALSE = use an off-screen pixmap for back buffer 595 * depth_size - requested bits/depth values, or zero 596 * stencil_size - requested bits/stencil values, or zero 597 * accum_red_size - requested bits/red accum values, or zero 598 * accum_green_size - requested bits/green accum values, or zero 599 * accum_blue_size - requested bits/blue accum values, or zero 600 * accum_alpha_size - requested bits/alpha accum values, or zero 601 * num_samples - number of samples/pixel if multisampling, or zero 602 * level - visual level, usually 0 603 * visualCaveat - ala the GLX extension, usually GLX_NONE 604 * Return; a new XMesaVisual or 0 if error. 605 */ 606PUBLIC 607XMesaVisual XMesaCreateVisual( Display *display, 608 XVisualInfo * visinfo, 609 GLboolean rgb_flag, 610 GLboolean alpha_flag, 611 GLboolean db_flag, 612 GLboolean stereo_flag, 613 GLboolean ximage_flag, 614 GLint depth_size, 615 GLint stencil_size, 616 GLint accum_red_size, 617 GLint accum_green_size, 618 GLint accum_blue_size, 619 GLint accum_alpha_size, 620 GLint num_samples, 621 GLint level, 622 GLint visualCaveat ) 623{ 624 XMesaVisual v; 625 GLint red_bits, green_bits, blue_bits, alpha_bits; 626 627 /* For debugging only */ 628 if (_mesa_getenv("MESA_XSYNC")) { 629 /* This makes debugging X easier. 630 * In your debugger, set a breakpoint on _XError to stop when an 631 * X protocol error is generated. 632 */ 633 XSynchronize( display, 1 ); 634 } 635 636 v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual); 637 if (!v) { 638 return NULL; 639 } 640 641 v->display = display; 642 643 /* Save a copy of the XVisualInfo struct because the user may X_mesa_free() 644 * the struct but we may need some of the information contained in it 645 * at a later time. 646 */ 647 v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo)); 648 if(!v->visinfo) { 649 _mesa_free(v); 650 return NULL; 651 } 652 MEMCPY(v->visinfo, visinfo, sizeof(*visinfo)); 653 654 v->ximage_flag = ximage_flag; 655 656 v->mesa_visual.redMask = visinfo->red_mask; 657 v->mesa_visual.greenMask = visinfo->green_mask; 658 v->mesa_visual.blueMask = visinfo->blue_mask; 659 v->mesa_visual.visualID = visinfo->visualid; 660 v->mesa_visual.screen = visinfo->screen; 661 662#if !(defined(__cplusplus) || defined(c_plusplus)) 663 v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class); 664#else 665 v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class); 666#endif 667 668 v->mesa_visual.visualRating = visualCaveat; 669 670 if (alpha_flag) 671 v->mesa_visual.alphaBits = 8; 672 673 (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 ); 674 675 { 676 const int xclass = v->mesa_visual.visualType; 677 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { 678 red_bits = _mesa_bitcount(GET_REDMASK(v)); 679 green_bits = _mesa_bitcount(GET_GREENMASK(v)); 680 blue_bits = _mesa_bitcount(GET_BLUEMASK(v)); 681 } 682 else { 683 /* this is an approximation */ 684 int depth; 685 depth = v->visinfo->depth; 686 red_bits = depth / 3; 687 depth -= red_bits; 688 green_bits = depth / 2; 689 depth -= green_bits; 690 blue_bits = depth; 691 alpha_bits = 0; 692 assert( red_bits + green_bits + blue_bits == v->visinfo->depth ); 693 } 694 alpha_bits = v->mesa_visual.alphaBits; 695 } 696 697 _mesa_initialize_visual( &v->mesa_visual, 698 rgb_flag, db_flag, stereo_flag, 699 red_bits, green_bits, 700 blue_bits, alpha_bits, 701 v->mesa_visual.indexBits, 702 depth_size, 703 stencil_size, 704 accum_red_size, accum_green_size, 705 accum_blue_size, accum_alpha_size, 706 0 ); 707 708 /* XXX minor hack */ 709 v->mesa_visual.level = level; 710 return v; 711} 712 713 714PUBLIC 715void XMesaDestroyVisual( XMesaVisual v ) 716{ 717 _mesa_free(v->visinfo); 718 _mesa_free(v); 719} 720 721 722 723/** 724 * Create a new XMesaContext. 725 * \param v the XMesaVisual 726 * \param share_list another XMesaContext with which to share display 727 * lists or NULL if no sharing is wanted. 728 * \return an XMesaContext or NULL if error. 729 */ 730PUBLIC 731XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list ) 732{ 733 static GLboolean firstTime = GL_TRUE; 734 struct pipe_winsys *winsys; 735 struct pipe_screen *screen; 736 struct pipe_context *pipe; 737 XMesaContext c; 738 GLcontext *mesaCtx; 739 uint pf; 740 741 if (firstTime) { 742 pipe_mutex_init(_xmesa_lock); 743 firstTime = GL_FALSE; 744 } 745 746 /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */ 747 c = (XMesaContext) CALLOC_STRUCT(xmesa_context); 748 if (!c) 749 return NULL; 750 751 pf = choose_pixel_format(v); 752 assert(pf); 753 754 c->xm_visual = v; 755 c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */ 756 757 /* XXX: create once per Xlib Display. 758 */ 759 winsys = xmesa_create_pipe_winsys(); 760 if (winsys == NULL) 761 goto fail; 762 763 /* XXX: create once per Xlib Display. 764 */ 765 screen = xmesa_create_pipe_screen( winsys ); 766 if (screen == NULL) 767 goto fail; 768 769 pipe = xmesa_create_pipe_context( screen, 770 (void *)c ); 771 if (pipe == NULL) 772 goto fail; 773 774 c->st = st_create_context(pipe, 775 &v->mesa_visual, 776 share_list ? share_list->st : NULL); 777 if (c->st == NULL) 778 goto fail; 779 780 mesaCtx = c->st->ctx; 781 c->st->ctx->DriverCtx = c; 782 783#if 00 784 _mesa_enable_sw_extensions(mesaCtx); 785 _mesa_enable_1_3_extensions(mesaCtx); 786 _mesa_enable_1_4_extensions(mesaCtx); 787 _mesa_enable_1_5_extensions(mesaCtx); 788 _mesa_enable_2_0_extensions(mesaCtx); 789#endif 790 791 return c; 792 793 fail: 794 if (c->st) 795 st_destroy_context(c->st); 796 else if (pipe) 797 pipe->destroy(pipe); 798 799 if (screen) 800 screen->destroy( screen ); 801 802 if (winsys) 803 winsys->destroy( winsys ); 804 805 FREE(c); 806 return NULL; 807} 808 809 810 811PUBLIC 812void XMesaDestroyContext( XMesaContext c ) 813{ 814 st_destroy_context(c->st); 815 816 /* FIXME: We should destroy the screen here, but if we do so, surfaces may 817 * outlive it, causing segfaults 818 struct pipe_screen *screen = c->st->pipe->screen; 819 screen->destroy(screen); 820 */ 821 822 _mesa_free(c); 823} 824 825 826 827/** 828 * Private function for creating an XMesaBuffer which corresponds to an 829 * X window or pixmap. 830 * \param v the window's XMesaVisual 831 * \param w the window we're wrapping 832 * \return new XMesaBuffer or NULL if error 833 */ 834PUBLIC XMesaBuffer 835XMesaCreateWindowBuffer(XMesaVisual v, Window w) 836{ 837 XWindowAttributes attr; 838 XMesaBuffer b; 839 Colormap cmap; 840 int depth; 841 842 assert(v); 843 assert(w); 844 845 /* Check that window depth matches visual depth */ 846 XGetWindowAttributes( v->display, w, &attr ); 847 depth = attr.depth; 848 if (v->visinfo->depth != depth) { 849 _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n", 850 v->visinfo->depth, depth); 851 return NULL; 852 } 853 854 /* Find colormap */ 855 if (attr.colormap) { 856 cmap = attr.colormap; 857 } 858 else { 859 _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w); 860 /* this is weird, a window w/out a colormap!? */ 861 /* OK, let's just allocate a new one and hope for the best */ 862 cmap = XCreateColormap(v->display, w, attr.visual, AllocNone); 863 } 864 865 b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap); 866 if (!b) 867 return NULL; 868 869 if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode, 870 (Drawable) w, cmap )) { 871 xmesa_free_buffer(b); 872 return NULL; 873 } 874 875 return b; 876} 877 878 879 880/** 881 * Create a new XMesaBuffer from an X pixmap. 882 * 883 * \param v the XMesaVisual 884 * \param p the pixmap 885 * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or 886 * \c GLX_DIRECT_COLOR visual for the pixmap 887 * \returns new XMesaBuffer or NULL if error 888 */ 889PUBLIC XMesaBuffer 890XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap) 891{ 892 XMesaBuffer b; 893 894 assert(v); 895 896 b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); 897 if (!b) 898 return NULL; 899 900 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, 901 (Drawable) p, cmap)) { 902 xmesa_free_buffer(b); 903 return NULL; 904 } 905 906 return b; 907} 908 909 910/** 911 * For GLX_EXT_texture_from_pixmap 912 */ 913XMesaBuffer 914XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p, 915 Colormap cmap, 916 int format, int target, int mipmap) 917{ 918 GET_CURRENT_CONTEXT(ctx); 919 XMesaBuffer b; 920 GLuint width, height; 921 922 assert(v); 923 924 b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); 925 if (!b) 926 return NULL; 927 928 /* get pixmap size, update framebuffer/renderbuffer dims */ 929 xmesa_get_window_size(v->display, b, &width, &height); 930 _mesa_resize_framebuffer(NULL, &(b->stfb->Base), width, height); 931 932 if (target == 0) { 933 /* examine dims */ 934 if (ctx->Extensions.ARB_texture_non_power_of_two) { 935 target = GLX_TEXTURE_2D_EXT; 936 } 937 else if ( _mesa_bitcount(width) == 1 938 && _mesa_bitcount(height) == 1) { 939 /* power of two size */ 940 if (height == 1) { 941 target = GLX_TEXTURE_1D_EXT; 942 } 943 else { 944 target = GLX_TEXTURE_2D_EXT; 945 } 946 } 947 else if (ctx->Extensions.NV_texture_rectangle) { 948 target = GLX_TEXTURE_RECTANGLE_EXT; 949 } 950 else { 951 /* non power of two textures not supported */ 952 XMesaDestroyBuffer(b); 953 return 0; 954 } 955 } 956 957 b->TextureTarget = target; 958 b->TextureFormat = format; 959 b->TextureMipmap = mipmap; 960 961 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, 962 (Drawable) p, cmap)) { 963 xmesa_free_buffer(b); 964 return NULL; 965 } 966 967 return b; 968} 969 970 971 972XMesaBuffer 973XMesaCreatePBuffer(XMesaVisual v, Colormap cmap, 974 unsigned int width, unsigned int height) 975{ 976 Window root; 977 Drawable drawable; /* X Pixmap Drawable */ 978 XMesaBuffer b; 979 980 /* allocate pixmap for front buffer */ 981 root = RootWindow( v->display, v->visinfo->screen ); 982 drawable = XCreatePixmap(v->display, root, width, height, 983 v->visinfo->depth); 984 if (!drawable) 985 return NULL; 986 987 b = create_xmesa_buffer(drawable, PBUFFER, v, cmap); 988 if (!b) 989 return NULL; 990 991 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, 992 drawable, cmap)) { 993 xmesa_free_buffer(b); 994 return NULL; 995 } 996 997 return b; 998} 999 1000 1001 1002/* 1003 * Deallocate an XMesaBuffer structure and all related info. 1004 */ 1005PUBLIC void 1006XMesaDestroyBuffer(XMesaBuffer b) 1007{ 1008 xmesa_free_buffer(b); 1009} 1010 1011 1012/** 1013 * Query the current window size and update the corresponding GLframebuffer 1014 * and all attached renderbuffers. 1015 * Called when: 1016 * 1. the first time a buffer is bound to a context. 1017 * 2. SwapBuffers. XXX probabaly from xm_flush_frontbuffer() too... 1018 * Note: it's possible (and legal) for xmctx to be NULL. That can happen 1019 * when resizing a buffer when no rendering context is bound. 1020 */ 1021void 1022xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer) 1023{ 1024 GLuint width, height; 1025 xmesa_get_window_size(drawBuffer->xm_visual->display, drawBuffer, &width, &height); 1026 st_resize_framebuffer(drawBuffer->stfb, width, height); 1027} 1028 1029 1030 1031 1032/* 1033 * Bind buffer b to context c and make c the current rendering context. 1034 */ 1035PUBLIC 1036GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer, 1037 XMesaBuffer readBuffer ) 1038{ 1039 if (c) { 1040 if (!drawBuffer || !readBuffer) 1041 return GL_FALSE; /* must specify buffers! */ 1042 1043#if 0 1044 /* XXX restore this optimization */ 1045 if (&(c->mesa) == _mesa_get_current_context() 1046 && c->mesa.DrawBuffer == &drawBuffer->mesa_buffer 1047 && c->mesa.ReadBuffer == &readBuffer->mesa_buffer 1048 && xmesa_buffer(c->mesa.DrawBuffer)->wasCurrent) { 1049 /* same context and buffer, do nothing */ 1050 return GL_TRUE; 1051 } 1052#endif 1053 1054 c->xm_buffer = drawBuffer; 1055 1056 /* Call this periodically to detect when the user has begun using 1057 * GL rendering from multiple threads. 1058 */ 1059 _glapi_check_multithread(); 1060 1061 st_make_current(c->st, drawBuffer->stfb, readBuffer->stfb); 1062 1063 xmesa_check_and_update_buffer_size(c, drawBuffer); 1064 if (readBuffer != drawBuffer) 1065 xmesa_check_and_update_buffer_size(c, readBuffer); 1066 1067 /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */ 1068 drawBuffer->wasCurrent = GL_TRUE; 1069 } 1070 else { 1071 /* Detach */ 1072 st_make_current( NULL, NULL, NULL ); 1073 } 1074 return GL_TRUE; 1075} 1076 1077 1078/* 1079 * Unbind the context c from its buffer. 1080 */ 1081GLboolean XMesaUnbindContext( XMesaContext c ) 1082{ 1083 /* A no-op for XFree86 integration purposes */ 1084 return GL_TRUE; 1085} 1086 1087 1088XMesaContext XMesaGetCurrentContext( void ) 1089{ 1090 GET_CURRENT_CONTEXT(ctx); 1091 if (ctx) { 1092 XMesaContext xmesa = xmesa_context(ctx); 1093 return xmesa; 1094 } 1095 else { 1096 return 0; 1097 } 1098} 1099 1100 1101 1102 1103 1104 1105/* 1106 * Copy the back buffer to the front buffer. If there's no back buffer 1107 * this is a no-op. 1108 */ 1109PUBLIC 1110void XMesaSwapBuffers( XMesaBuffer b ) 1111{ 1112 struct pipe_surface *surf; 1113 1114 /* If we're swapping the buffer associated with the current context 1115 * we have to flush any pending rendering commands first. 1116 */ 1117 st_notify_swapbuffers(b->stfb); 1118 1119 surf = st_get_framebuffer_surface(b->stfb, ST_SURFACE_BACK_LEFT); 1120 if (surf) { 1121 xmesa_display_surface(b, surf); 1122// xmesa_display_surface(b, surf); 1123 } 1124 1125 xmesa_check_and_update_buffer_size(NULL, b); 1126} 1127 1128 1129 1130/* 1131 * Copy sub-region of back buffer to front buffer 1132 */ 1133void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height ) 1134{ 1135 struct pipe_surface *surf_front 1136 = st_get_framebuffer_surface(b->stfb, ST_SURFACE_FRONT_LEFT); 1137 struct pipe_surface *surf_back 1138 = st_get_framebuffer_surface(b->stfb, ST_SURFACE_BACK_LEFT); 1139 struct pipe_context *pipe = NULL; /* XXX fix */ 1140 1141 if (!surf_front || !surf_back) 1142 return; 1143 1144 pipe->surface_copy(pipe, 1145 FALSE, 1146 surf_front, x, y, /* dest */ 1147 surf_back, x, y, /* src */ 1148 width, height); 1149} 1150 1151 1152 1153void XMesaFlush( XMesaContext c ) 1154{ 1155 if (c && c->xm_visual->display) { 1156 st_finish(c->st); 1157 XSync( c->xm_visual->display, False ); 1158 } 1159} 1160 1161 1162 1163 1164 1165XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d ) 1166{ 1167 XMesaBuffer b; 1168 for (b=XMesaBufferList; b; b=b->Next) { 1169 if (b->drawable == d && b->xm_visual->display == dpy) { 1170 return b; 1171 } 1172 } 1173 return NULL; 1174} 1175 1176 1177/** 1178 * Free/destroy all XMesaBuffers associated with given display. 1179 */ 1180void xmesa_destroy_buffers_on_display(Display *dpy) 1181{ 1182 XMesaBuffer b, next; 1183 for (b = XMesaBufferList; b; b = next) { 1184 next = b->Next; 1185 if (b->xm_visual->display == dpy) { 1186 xmesa_free_buffer(b); 1187 } 1188 } 1189} 1190 1191 1192/* 1193 * Look for XMesaBuffers whose X window has been destroyed. 1194 * Deallocate any such XMesaBuffers. 1195 */ 1196void XMesaGarbageCollect( void ) 1197{ 1198 XMesaBuffer b, next; 1199 for (b=XMesaBufferList; b; b=next) { 1200 next = b->Next; 1201 if (b->xm_visual && 1202 b->xm_visual->display && 1203 b->drawable && 1204 b->type == WINDOW) { 1205 XSync(b->xm_visual->display, False); 1206 if (!window_exists( b->xm_visual->display, b->drawable )) { 1207 /* found a dead window, free the ancillary info */ 1208 XMesaDestroyBuffer( b ); 1209 } 1210 } 1211 } 1212} 1213 1214 1215 1216 1217PUBLIC void 1218XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, 1219 const int *attrib_list) 1220{ 1221} 1222 1223 1224 1225PUBLIC void 1226XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer) 1227{ 1228} 1229 1230