xm_api.c revision bc63b226bcc94f109906bccce26d47509f28d177
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. In 52 * Mesa, when byte swapping is needed we use the PF_TRUECOLOR pixel format 53 * and use XPutPixel everywhere except in the implementation of 54 * glClear(GL_COLOR_BUFFER_BIT). We want this function to be fast so 55 * instead of using XPutPixel we "poke" our values after byte-swapping 56 * the clear pixel value if needed. 57 * 58 */ 59 60#ifdef __CYGWIN__ 61#undef WIN32 62#undef __WIN32__ 63#endif 64 65#include "glxheader.h" 66#include "xmesaP.h" 67#include "main/context.h" 68#include "main/extensions.h" 69#include "main/framebuffer.h" 70#include "main/imports.h" 71#include "main/macros.h" 72#include "main/renderbuffer.h" 73#include "main/teximage.h" 74#include "glapi/glthread.h" 75#include "swrast/swrast.h" 76#include "swrast_setup/swrast_setup.h" 77#include "vbo/vbo.h" 78#include "tnl/tnl.h" 79#include "tnl/t_context.h" 80#include "tnl/t_pipeline.h" 81#include "drivers/common/driverfuncs.h" 82#include "drivers/common/meta.h" 83 84/** 85 * Global X driver lock 86 */ 87_glthread_Mutex _xmesa_lock; 88 89 90 91/**********************************************************************/ 92/***** X Utility Functions *****/ 93/**********************************************************************/ 94 95 96/** 97 * Return the host's byte order as LSBFirst or MSBFirst ala X. 98 */ 99static int host_byte_order( void ) 100{ 101 int i = 1; 102 char *cptr = (char *) &i; 103 return (*cptr==1) ? LSBFirst : MSBFirst; 104} 105 106 107/** 108 * Check if the X Shared Memory extension is available. 109 * Return: 0 = not available 110 * 1 = shared XImage support available 111 * 2 = shared Pixmap support available also 112 */ 113static int check_for_xshm( XMesaDisplay *display ) 114{ 115#if defined(USE_XSHM) 116 int major, minor, ignore; 117 Bool pixmaps; 118 119 if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) { 120 if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) { 121 return (pixmaps==True) ? 2 : 1; 122 } 123 else { 124 return 0; 125 } 126 } 127 else { 128 return 0; 129 } 130#else 131 /* No XSHM support */ 132 return 0; 133#endif 134} 135 136 137/** 138 * Apply gamma correction to an intensity value in [0..max]. Return the 139 * new intensity value. 140 */ 141static GLint 142gamma_adjust( GLfloat gamma, GLint value, GLint max ) 143{ 144 if (gamma == 1.0) { 145 return value; 146 } 147 else { 148 double x = (double) value / (double) max; 149 return IROUND_POS((GLfloat) max * pow(x, 1.0F/gamma)); 150 } 151} 152 153 154 155/** 156 * Return the true number of bits per pixel for XImages. 157 * For example, if we request a 24-bit deep visual we may actually need/get 158 * 32bpp XImages. This function returns the appropriate bpp. 159 * Input: dpy - the X display 160 * visinfo - desribes the visual to be used for XImages 161 * Return: true number of bits per pixel for XImages 162 */ 163static int 164bits_per_pixel( XMesaVisual xmv ) 165{ 166 XMesaDisplay *dpy = xmv->display; 167 XMesaVisualInfo visinfo = xmv->visinfo; 168 XMesaImage *img; 169 int bitsPerPixel; 170 /* Create a temporary XImage */ 171 img = XCreateImage( dpy, visinfo->visual, visinfo->depth, 172 ZPixmap, 0, /*format, offset*/ 173 (char*) MALLOC(8), /*data*/ 174 1, 1, /*width, height*/ 175 32, /*bitmap_pad*/ 176 0 /*bytes_per_line*/ 177 ); 178 assert(img); 179 /* grab the bits/pixel value */ 180 bitsPerPixel = img->bits_per_pixel; 181 /* free the XImage */ 182 free( img->data ); 183 img->data = NULL; 184 XMesaDestroyImage( img ); 185 return bitsPerPixel; 186} 187 188 189 190/* 191 * Determine if a given X window ID is valid (window exists). 192 * Do this by calling XGetWindowAttributes() for the window and 193 * checking if we catch an X error. 194 * Input: dpy - the display 195 * win - the window to check for existance 196 * Return: GL_TRUE - window exists 197 * GL_FALSE - window doesn't exist 198 */ 199static GLboolean WindowExistsFlag; 200 201static int window_exists_err_handler( XMesaDisplay* dpy, XErrorEvent* xerr ) 202{ 203 (void) dpy; 204 if (xerr->error_code == BadWindow) { 205 WindowExistsFlag = GL_FALSE; 206 } 207 return 0; 208} 209 210static GLboolean window_exists( XMesaDisplay *dpy, Window win ) 211{ 212 XWindowAttributes wa; 213 int (*old_handler)( XMesaDisplay*, XErrorEvent* ); 214 WindowExistsFlag = GL_TRUE; 215 old_handler = XSetErrorHandler(window_exists_err_handler); 216 XGetWindowAttributes( dpy, win, &wa ); /* dummy request */ 217 XSetErrorHandler(old_handler); 218 return WindowExistsFlag; 219} 220 221static Status 222get_drawable_size( XMesaDisplay *dpy, Drawable d, GLuint *width, GLuint *height ) 223{ 224 Window root; 225 Status stat; 226 int xpos, ypos; 227 unsigned int w, h, bw, depth; 228 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); 229 *width = w; 230 *height = h; 231 return stat; 232} 233 234 235/** 236 * Return the size of the window (or pixmap) that corresponds to the 237 * given XMesaBuffer. 238 * \param width returns width in pixels 239 * \param height returns height in pixels 240 */ 241void 242xmesa_get_window_size(XMesaDisplay *dpy, XMesaBuffer b, 243 GLuint *width, GLuint *height) 244{ 245 Status stat; 246 247 _glthread_LOCK_MUTEX(_xmesa_lock); 248 XSync(b->xm_visual->display, 0); /* added for Chromium */ 249 stat = get_drawable_size(dpy, b->frontxrb->pixmap, width, height); 250 _glthread_UNLOCK_MUTEX(_xmesa_lock); 251 252 if (!stat) { 253 /* probably querying a window that's recently been destroyed */ 254 _mesa_warning(NULL, "XGetGeometry failed!\n"); 255 *width = *height = 1; 256 } 257} 258 259 260 261/**********************************************************************/ 262/***** Linked list of XMesaBuffers *****/ 263/**********************************************************************/ 264 265XMesaBuffer XMesaBufferList = NULL; 266 267 268/** 269 * Allocate a new XMesaBuffer object which corresponds to the given drawable. 270 * Note that XMesaBuffer is derived from struct gl_framebuffer. 271 * The new XMesaBuffer will not have any size (Width=Height=0). 272 * 273 * \param d the corresponding X drawable (window or pixmap) 274 * \param type either WINDOW, PIXMAP or PBUFFER, describing d 275 * \param vis the buffer's visual 276 * \param cmap the window's colormap, if known. 277 * \return new XMesaBuffer or NULL if any problem 278 */ 279static XMesaBuffer 280create_xmesa_buffer(XMesaDrawable d, BufferType type, 281 XMesaVisual vis, XMesaColormap cmap) 282{ 283 XMesaBuffer b; 284 285 ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER); 286 287 b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer); 288 if (!b) 289 return NULL; 290 291 b->display = vis->display; 292 b->xm_visual = vis; 293 b->type = type; 294 b->cmap = cmap; 295 296 _mesa_initialize_window_framebuffer(&b->mesa_buffer, &vis->mesa_visual); 297 b->mesa_buffer.Delete = xmesa_delete_framebuffer; 298 299 /* 300 * Front renderbuffer 301 */ 302 b->frontxrb = xmesa_new_renderbuffer(NULL, 0, vis, GL_FALSE); 303 if (!b->frontxrb) { 304 free(b); 305 return NULL; 306 } 307 b->frontxrb->Parent = b; 308 b->frontxrb->drawable = d; 309 b->frontxrb->pixmap = (XMesaPixmap) d; 310 _mesa_add_renderbuffer(&b->mesa_buffer, BUFFER_FRONT_LEFT, 311 &b->frontxrb->Base); 312 313 /* 314 * Back renderbuffer 315 */ 316 if (vis->mesa_visual.doubleBufferMode) { 317 b->backxrb = xmesa_new_renderbuffer(NULL, 0, vis, GL_TRUE); 318 if (!b->backxrb) { 319 /* XXX free front xrb too */ 320 free(b); 321 return NULL; 322 } 323 b->backxrb->Parent = b; 324 /* determine back buffer implementation */ 325 b->db_mode = vis->ximage_flag ? BACK_XIMAGE : BACK_PIXMAP; 326 327 _mesa_add_renderbuffer(&b->mesa_buffer, BUFFER_BACK_LEFT, 328 &b->backxrb->Base); 329 } 330 331 /* 332 * Other renderbuffer (depth, stencil, etc) 333 */ 334 _mesa_add_soft_renderbuffers(&b->mesa_buffer, 335 GL_FALSE, /* color */ 336 vis->mesa_visual.haveDepthBuffer, 337 vis->mesa_visual.haveStencilBuffer, 338 vis->mesa_visual.haveAccumBuffer, 339 GL_FALSE, /* software alpha buffer */ 340 vis->mesa_visual.numAuxBuffers > 0 ); 341 342 /* GLX_EXT_texture_from_pixmap */ 343 b->TextureTarget = 0; 344 b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT; 345 b->TextureMipmap = 0; 346 347 /* insert buffer into linked list */ 348 b->Next = XMesaBufferList; 349 XMesaBufferList = b; 350 351 return b; 352} 353 354 355/** 356 * Find an XMesaBuffer by matching X display and colormap but NOT matching 357 * the notThis buffer. 358 */ 359XMesaBuffer 360xmesa_find_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis) 361{ 362 XMesaBuffer b; 363 for (b=XMesaBufferList; b; b=b->Next) { 364 if (b->display==dpy && b->cmap==cmap && b!=notThis) { 365 return b; 366 } 367 } 368 return NULL; 369} 370 371 372/** 373 * Remove buffer from linked list, delete if no longer referenced. 374 */ 375static void 376xmesa_free_buffer(XMesaBuffer buffer) 377{ 378 XMesaBuffer prev = NULL, b; 379 380 for (b = XMesaBufferList; b; b = b->Next) { 381 if (b == buffer) { 382 struct gl_framebuffer *fb = &buffer->mesa_buffer; 383 384 /* unlink buffer from list */ 385 if (prev) 386 prev->Next = buffer->Next; 387 else 388 XMesaBufferList = buffer->Next; 389 390 /* mark as delete pending */ 391 fb->DeletePending = GL_TRUE; 392 393 /* Since the X window for the XMesaBuffer is going away, we don't 394 * want to dereference this pointer in the future. 395 */ 396 b->frontxrb->drawable = 0; 397 398 /* Unreference. If count = zero we'll really delete the buffer */ 399 _mesa_reference_framebuffer(&fb, NULL); 400 401 return; 402 } 403 /* continue search */ 404 prev = b; 405 } 406 /* buffer not found in XMesaBufferList */ 407 _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n"); 408} 409 410 411 412 413/**********************************************************************/ 414/***** Misc Private Functions *****/ 415/**********************************************************************/ 416 417 418/** 419 * Setup RGB rendering for a window with a True/DirectColor visual. 420 */ 421static void 422setup_truecolor(XMesaVisual v, XMesaBuffer buffer, XMesaColormap cmap) 423{ 424 unsigned long rmask, gmask, bmask; 425 (void) buffer; 426 (void) cmap; 427 428 /* Compute red multiplier (mask) and bit shift */ 429 v->rshift = 0; 430 rmask = GET_REDMASK(v); 431 while ((rmask & 1)==0) { 432 v->rshift++; 433 rmask = rmask >> 1; 434 } 435 436 /* Compute green multiplier (mask) and bit shift */ 437 v->gshift = 0; 438 gmask = GET_GREENMASK(v); 439 while ((gmask & 1)==0) { 440 v->gshift++; 441 gmask = gmask >> 1; 442 } 443 444 /* Compute blue multiplier (mask) and bit shift */ 445 v->bshift = 0; 446 bmask = GET_BLUEMASK(v); 447 while ((bmask & 1)==0) { 448 v->bshift++; 449 bmask = bmask >> 1; 450 } 451 452 /* 453 * Compute component-to-pixel lookup tables and dithering kernel 454 */ 455 { 456 static GLubyte kernel[16] = { 457 0*16, 8*16, 2*16, 10*16, 458 12*16, 4*16, 14*16, 6*16, 459 3*16, 11*16, 1*16, 9*16, 460 15*16, 7*16, 13*16, 5*16, 461 }; 462 GLint rBits = _mesa_bitcount(rmask); 463 GLint gBits = _mesa_bitcount(gmask); 464 GLint bBits = _mesa_bitcount(bmask); 465 GLint maxBits; 466 GLuint i; 467 468 /* convert pixel components in [0,_mask] to RGB values in [0,255] */ 469 for (i=0; i<=rmask; i++) 470 v->PixelToR[i] = (unsigned char) ((i * 255) / rmask); 471 for (i=0; i<=gmask; i++) 472 v->PixelToG[i] = (unsigned char) ((i * 255) / gmask); 473 for (i=0; i<=bmask; i++) 474 v->PixelToB[i] = (unsigned char) ((i * 255) / bmask); 475 476 /* convert RGB values from [0,255] to pixel components */ 477 478 for (i=0;i<256;i++) { 479 GLint r = gamma_adjust(v->RedGamma, i, 255); 480 GLint g = gamma_adjust(v->GreenGamma, i, 255); 481 GLint b = gamma_adjust(v->BlueGamma, i, 255); 482 v->RtoPixel[i] = (r >> (8-rBits)) << v->rshift; 483 v->GtoPixel[i] = (g >> (8-gBits)) << v->gshift; 484 v->BtoPixel[i] = (b >> (8-bBits)) << v->bshift; 485 } 486 /* overflow protection */ 487 for (i=256;i<512;i++) { 488 v->RtoPixel[i] = v->RtoPixel[255]; 489 v->GtoPixel[i] = v->GtoPixel[255]; 490 v->BtoPixel[i] = v->BtoPixel[255]; 491 } 492 493 /* setup dithering kernel */ 494 maxBits = rBits; 495 if (gBits > maxBits) maxBits = gBits; 496 if (bBits > maxBits) maxBits = bBits; 497 for (i=0;i<16;i++) { 498 v->Kernel[i] = kernel[i] >> maxBits; 499 } 500 501 v->undithered_pf = PF_Truecolor; 502 v->dithered_pf = (GET_VISUAL_DEPTH(v)<24) ? PF_Dither_True : PF_Truecolor; 503 } 504 505 /* 506 * Now check for TrueColor visuals which we can optimize. 507 */ 508 if ( GET_REDMASK(v) ==0x0000ff 509 && GET_GREENMASK(v)==0x00ff00 510 && GET_BLUEMASK(v) ==0xff0000 511 && CHECK_BYTE_ORDER(v) 512 && v->BitsPerPixel==32 513 && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) { 514 /* common 32 bpp config used on SGI, Sun */ 515 v->undithered_pf = v->dithered_pf = PF_8A8B8G8R; /* ABGR */ 516 } 517 else if (GET_REDMASK(v) == 0xff0000 518 && GET_GREENMASK(v)== 0x00ff00 519 && GET_BLUEMASK(v) == 0x0000ff 520 && CHECK_BYTE_ORDER(v) 521 && v->RedGamma == 1.0 && v->GreenGamma == 1.0 && v->BlueGamma == 1.0){ 522 if (v->BitsPerPixel==32) { 523 /* if 32 bpp, and visual indicates 8 bpp alpha channel */ 524 if (GET_VISUAL_DEPTH(v) == 32 && v->mesa_visual.alphaBits == 8) 525 v->undithered_pf = v->dithered_pf = PF_8A8R8G8B; /* ARGB */ 526 else 527 v->undithered_pf = v->dithered_pf = PF_8R8G8B; /* xRGB */ 528 } 529 else if (v->BitsPerPixel == 24) { 530 v->undithered_pf = v->dithered_pf = PF_8R8G8B24; /* RGB */ 531 } 532 } 533 else if (GET_REDMASK(v) ==0xf800 534 && GET_GREENMASK(v)==0x07e0 535 && GET_BLUEMASK(v) ==0x001f 536 && CHECK_BYTE_ORDER(v) 537 && v->BitsPerPixel==16 538 && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) { 539 /* 5-6-5 RGB */ 540 v->undithered_pf = PF_5R6G5B; 541 v->dithered_pf = PF_Dither_5R6G5B; 542 } 543} 544 545 546/** 547 * When a context is bound for the first time, we can finally finish 548 * initializing the context's visual and buffer information. 549 * \param v the XMesaVisual to initialize 550 * \param b the XMesaBuffer to initialize (may be NULL) 551 * \param rgb_flag TRUE = RGBA mode, FALSE = color index mode 552 * \param window the window/pixmap we're rendering into 553 * \param cmap the colormap associated with the window/pixmap 554 * \return GL_TRUE=success, GL_FALSE=failure 555 */ 556static GLboolean 557initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b, 558 XMesaDrawable window, 559 XMesaColormap cmap) 560{ 561 const int xclass = v->visualType; 562 563 564 ASSERT(!b || b->xm_visual == v); 565 566 /* Save true bits/pixel */ 567 v->BitsPerPixel = bits_per_pixel(v); 568 assert(v->BitsPerPixel > 0); 569 570 /* RGB WINDOW: 571 * We support RGB rendering into almost any kind of visual. 572 */ 573 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { 574 setup_truecolor( v, b, cmap ); 575 } 576 else { 577 _mesa_warning(NULL, "XMesa: RGB mode rendering not supported in given visual.\n"); 578 return GL_FALSE; 579 } 580 v->mesa_visual.indexBits = 0; 581 582 if (_mesa_getenv("MESA_NO_DITHER")) { 583 v->dithered_pf = v->undithered_pf; 584 } 585 586 587 /* 588 * If MESA_INFO env var is set print out some debugging info 589 * which can help Brian figure out what's going on when a user 590 * reports bugs. 591 */ 592 if (_mesa_getenv("MESA_INFO")) { 593 printf("X/Mesa visual = %p\n", (void *) v); 594 printf("X/Mesa dithered pf = %u\n", v->dithered_pf); 595 printf("X/Mesa undithered pf = %u\n", v->undithered_pf); 596 printf("X/Mesa level = %d\n", v->mesa_visual.level); 597 printf("X/Mesa depth = %d\n", GET_VISUAL_DEPTH(v)); 598 printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel); 599 } 600 601 if (b && window) { 602 char *data; 603 604 /* Do window-specific initializations */ 605 606 /* these should have been set in create_xmesa_buffer */ 607 ASSERT(b->frontxrb->drawable == window); 608 ASSERT(b->frontxrb->pixmap == (XMesaPixmap) window); 609 610 /* Setup for single/double buffering */ 611 if (v->mesa_visual.doubleBufferMode) { 612 /* Double buffered */ 613 b->shm = check_for_xshm( v->display ); 614 } 615 616 /* X11 graphics contexts */ 617 b->gc = XCreateGC( v->display, window, 0, NULL ); 618 XMesaSetFunction( v->display, b->gc, GXcopy ); 619 620 /* cleargc - for glClear() */ 621 b->cleargc = XCreateGC( v->display, window, 0, NULL ); 622 XMesaSetFunction( v->display, b->cleargc, GXcopy ); 623 624 /* 625 * Don't generate Graphics Expose/NoExpose events in swapbuffers(). 626 * Patch contributed by Michael Pichler May 15, 1995. 627 */ 628 { 629 XGCValues gcvalues; 630 gcvalues.graphics_exposures = False; 631 b->swapgc = XCreateGC(v->display, window, 632 GCGraphicsExposures, &gcvalues); 633 } 634 XMesaSetFunction( v->display, b->swapgc, GXcopy ); 635 636 /* Initialize the row buffer XImage for use in write_color_span() */ 637 data = (char*) MALLOC(MAX_WIDTH*4); 638 b->rowimage = XCreateImage( v->display, 639 v->visinfo->visual, 640 v->visinfo->depth, 641 ZPixmap, 0, /*format, offset*/ 642 data, /*data*/ 643 MAX_WIDTH, 1, /*width, height*/ 644 32, /*bitmap_pad*/ 645 0 /*bytes_per_line*/ ); 646 if (!b->rowimage) 647 return GL_FALSE; 648 } 649 650 return GL_TRUE; 651} 652 653 654 655/* 656 * Convert an RGBA color to a pixel value. 657 */ 658unsigned long 659xmesa_color_to_pixel(struct gl_context *ctx, 660 GLubyte r, GLubyte g, GLubyte b, GLubyte a, 661 GLuint pixelFormat) 662{ 663 XMesaContext xmesa = XMESA_CONTEXT(ctx); 664 switch (pixelFormat) { 665 case PF_Truecolor: 666 { 667 unsigned long p; 668 PACK_TRUECOLOR( p, r, g, b ); 669 return p; 670 } 671 case PF_8A8B8G8R: 672 return PACK_8A8B8G8R( r, g, b, a ); 673 case PF_8A8R8G8B: 674 return PACK_8A8R8G8B( r, g, b, a ); 675 case PF_8R8G8B: 676 /* fall through */ 677 case PF_8R8G8B24: 678 return PACK_8R8G8B( r, g, b ); 679 case PF_5R6G5B: 680 return PACK_5R6G5B( r, g, b ); 681 case PF_Dither_True: 682 /* fall through */ 683 case PF_Dither_5R6G5B: 684 { 685 unsigned long p; 686 PACK_TRUEDITHER(p, 1, 0, r, g, b); 687 return p; 688 } 689 default: 690 _mesa_problem(ctx, "Bad pixel format in xmesa_color_to_pixel"); 691 } 692 return 0; 693} 694 695 696#define NUM_VISUAL_TYPES 6 697 698/** 699 * Convert an X visual type to a GLX visual type. 700 * 701 * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) 702 * to be converted. 703 * \return If \c visualType is a valid X visual type, a GLX visual type will 704 * be returned. Otherwise \c GLX_NONE will be returned. 705 * 706 * \note 707 * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the 708 * DRI CVS tree. 709 */ 710static GLint 711xmesa_convert_from_x_visual_type( int visualType ) 712{ 713 static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { 714 GLX_STATIC_GRAY, GLX_GRAY_SCALE, 715 GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, 716 GLX_TRUE_COLOR, GLX_DIRECT_COLOR 717 }; 718 719 return ( (unsigned) visualType < NUM_VISUAL_TYPES ) 720 ? glx_visual_types[ visualType ] : GLX_NONE; 721} 722 723 724/**********************************************************************/ 725/***** Public Functions *****/ 726/**********************************************************************/ 727 728 729/* 730 * Create a new X/Mesa visual. 731 * Input: display - X11 display 732 * visinfo - an XVisualInfo pointer 733 * rgb_flag - GL_TRUE = RGB mode, 734 * GL_FALSE = color index mode 735 * alpha_flag - alpha buffer requested? 736 * db_flag - GL_TRUE = double-buffered, 737 * GL_FALSE = single buffered 738 * stereo_flag - stereo visual? 739 * ximage_flag - GL_TRUE = use an XImage for back buffer, 740 * GL_FALSE = use an off-screen pixmap for back buffer 741 * depth_size - requested bits/depth values, or zero 742 * stencil_size - requested bits/stencil values, or zero 743 * accum_red_size - requested bits/red accum values, or zero 744 * accum_green_size - requested bits/green accum values, or zero 745 * accum_blue_size - requested bits/blue accum values, or zero 746 * accum_alpha_size - requested bits/alpha accum values, or zero 747 * num_samples - number of samples/pixel if multisampling, or zero 748 * level - visual level, usually 0 749 * visualCaveat - ala the GLX extension, usually GLX_NONE 750 * Return; a new XMesaVisual or 0 if error. 751 */ 752PUBLIC 753XMesaVisual XMesaCreateVisual( XMesaDisplay *display, 754 XMesaVisualInfo visinfo, 755 GLboolean rgb_flag, 756 GLboolean alpha_flag, 757 GLboolean db_flag, 758 GLboolean stereo_flag, 759 GLboolean ximage_flag, 760 GLint depth_size, 761 GLint stencil_size, 762 GLint accum_red_size, 763 GLint accum_green_size, 764 GLint accum_blue_size, 765 GLint accum_alpha_size, 766 GLint num_samples, 767 GLint level, 768 GLint visualCaveat ) 769{ 770 char *gamma; 771 XMesaVisual v; 772 GLint red_bits, green_bits, blue_bits, alpha_bits; 773 774 /* For debugging only */ 775 if (_mesa_getenv("MESA_XSYNC")) { 776 /* This makes debugging X easier. 777 * In your debugger, set a breakpoint on _XError to stop when an 778 * X protocol error is generated. 779 */ 780 XSynchronize( display, 1 ); 781 } 782 783 /* Color-index rendering not supported. */ 784 if (!rgb_flag) 785 return NULL; 786 787 v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual); 788 if (!v) { 789 return NULL; 790 } 791 792 v->display = display; 793 794 /* Save a copy of the XVisualInfo struct because the user may Xfree() 795 * the struct but we may need some of the information contained in it 796 * at a later time. 797 */ 798 v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo)); 799 if(!v->visinfo) { 800 free(v); 801 return NULL; 802 } 803 memcpy(v->visinfo, visinfo, sizeof(*visinfo)); 804 805 /* check for MESA_GAMMA environment variable */ 806 gamma = _mesa_getenv("MESA_GAMMA"); 807 if (gamma) { 808 v->RedGamma = v->GreenGamma = v->BlueGamma = 0.0; 809 sscanf( gamma, "%f %f %f", &v->RedGamma, &v->GreenGamma, &v->BlueGamma ); 810 if (v->RedGamma<=0.0) v->RedGamma = 1.0; 811 if (v->GreenGamma<=0.0) v->GreenGamma = v->RedGamma; 812 if (v->BlueGamma<=0.0) v->BlueGamma = v->RedGamma; 813 } 814 else { 815 v->RedGamma = v->GreenGamma = v->BlueGamma = 1.0; 816 } 817 818 v->ximage_flag = ximage_flag; 819 820 v->mesa_visual.redMask = visinfo->red_mask; 821 v->mesa_visual.greenMask = visinfo->green_mask; 822 v->mesa_visual.blueMask = visinfo->blue_mask; 823 v->visualID = visinfo->visualid; 824 v->screen = visinfo->screen; 825 826#if !(defined(__cplusplus) || defined(c_plusplus)) 827 v->visualType = xmesa_convert_from_x_visual_type(visinfo->class); 828#else 829 v->visualType = xmesa_convert_from_x_visual_type(visinfo->c_class); 830#endif 831 832 v->mesa_visual.visualRating = visualCaveat; 833 834 if (alpha_flag) 835 v->mesa_visual.alphaBits = 8; 836 837 (void) initialize_visual_and_buffer( v, NULL, 0, 0 ); 838 839 { 840 const int xclass = v->visualType; 841 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { 842 red_bits = _mesa_bitcount(GET_REDMASK(v)); 843 green_bits = _mesa_bitcount(GET_GREENMASK(v)); 844 blue_bits = _mesa_bitcount(GET_BLUEMASK(v)); 845 } 846 else { 847 /* this is an approximation */ 848 int depth; 849 depth = GET_VISUAL_DEPTH(v); 850 red_bits = depth / 3; 851 depth -= red_bits; 852 green_bits = depth / 2; 853 depth -= green_bits; 854 blue_bits = depth; 855 alpha_bits = 0; 856 assert( red_bits + green_bits + blue_bits == GET_VISUAL_DEPTH(v) ); 857 } 858 alpha_bits = v->mesa_visual.alphaBits; 859 } 860 861 _mesa_initialize_visual( &v->mesa_visual, 862 db_flag, stereo_flag, 863 red_bits, green_bits, 864 blue_bits, alpha_bits, 865 depth_size, 866 stencil_size, 867 accum_red_size, accum_green_size, 868 accum_blue_size, accum_alpha_size, 869 0 ); 870 871 /* XXX minor hack */ 872 v->mesa_visual.level = level; 873 return v; 874} 875 876 877PUBLIC 878void XMesaDestroyVisual( XMesaVisual v ) 879{ 880 free(v->visinfo); 881 free(v); 882} 883 884 885 886/** 887 * Create a new XMesaContext. 888 * \param v the XMesaVisual 889 * \param share_list another XMesaContext with which to share display 890 * lists or NULL if no sharing is wanted. 891 * \return an XMesaContext or NULL if error. 892 */ 893PUBLIC 894XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list ) 895{ 896 static GLboolean firstTime = GL_TRUE; 897 XMesaContext c; 898 struct gl_context *mesaCtx; 899 struct dd_function_table functions; 900 TNLcontext *tnl; 901 902 if (firstTime) { 903 _glthread_INIT_MUTEX(_xmesa_lock); 904 firstTime = GL_FALSE; 905 } 906 907 /* Note: the XMesaContext contains a Mesa struct gl_context struct (inheritance) */ 908 c = (XMesaContext) CALLOC_STRUCT(xmesa_context); 909 if (!c) 910 return NULL; 911 912 mesaCtx = &(c->mesa); 913 914 /* initialize with default driver functions, then plug in XMesa funcs */ 915 _mesa_init_driver_functions(&functions); 916 xmesa_init_driver_functions(v, &functions); 917 if (!_mesa_initialize_context(mesaCtx, API_OPENGL, &v->mesa_visual, 918 share_list ? &(share_list->mesa) : (struct gl_context *) NULL, 919 &functions, (void *) c)) { 920 free(c); 921 return NULL; 922 } 923 924 /* Enable this to exercise fixed function -> shader translation 925 * with software rendering. 926 */ 927 if (0) { 928 mesaCtx->VertexProgram._MaintainTnlProgram = GL_TRUE; 929 mesaCtx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; 930 } 931 932 _mesa_enable_sw_extensions(mesaCtx); 933 _mesa_enable_1_3_extensions(mesaCtx); 934 _mesa_enable_1_4_extensions(mesaCtx); 935 _mesa_enable_1_5_extensions(mesaCtx); 936 _mesa_enable_2_0_extensions(mesaCtx); 937 _mesa_enable_2_1_extensions(mesaCtx); 938#if ENABLE_EXT_texure_compression_s3tc 939 if (mesaCtx->Mesa_DXTn) { 940 _mesa_enable_extension(mesaCtx, "GL_EXT_texture_compression_s3tc"); 941 _mesa_enable_extension(mesaCtx, "GL_S3_s3tc"); 942 } 943 _mesa_enable_extension(mesaCtx, "GL_3DFX_texture_compression_FXT1"); 944#endif 945#if ENABLE_EXT_timer_query 946 _mesa_enable_extension(mesaCtx, "GL_EXT_timer_query"); 947#endif 948 949 950 /* finish up xmesa context initializations */ 951 c->swapbytes = CHECK_BYTE_ORDER(v) ? GL_FALSE : GL_TRUE; 952 c->xm_visual = v; 953 c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */ 954 c->display = v->display; 955 c->pixelformat = v->dithered_pf; /* Dithering is enabled by default */ 956 957 /* Initialize the software rasterizer and helper modules. 958 */ 959 if (!_swrast_CreateContext( mesaCtx ) || 960 !_vbo_CreateContext( mesaCtx ) || 961 !_tnl_CreateContext( mesaCtx ) || 962 !_swsetup_CreateContext( mesaCtx )) { 963 _mesa_free_context_data(&c->mesa); 964 free(c); 965 return NULL; 966 } 967 968 /* tnl setup */ 969 tnl = TNL_CONTEXT(mesaCtx); 970 tnl->Driver.RunPipeline = _tnl_run_pipeline; 971 /* swrast setup */ 972 xmesa_register_swrast_functions( mesaCtx ); 973 _swsetup_Wakeup(mesaCtx); 974 975 _mesa_meta_init(mesaCtx); 976 977 return c; 978} 979 980 981 982PUBLIC 983void XMesaDestroyContext( XMesaContext c ) 984{ 985 struct gl_context *mesaCtx = &c->mesa; 986 987 _mesa_meta_free( mesaCtx ); 988 989 _swsetup_DestroyContext( mesaCtx ); 990 _swrast_DestroyContext( mesaCtx ); 991 _tnl_DestroyContext( mesaCtx ); 992 _vbo_DestroyContext( mesaCtx ); 993 _mesa_free_context_data( mesaCtx ); 994 free( c ); 995} 996 997 998 999/** 1000 * Private function for creating an XMesaBuffer which corresponds to an 1001 * X window or pixmap. 1002 * \param v the window's XMesaVisual 1003 * \param w the window we're wrapping 1004 * \return new XMesaBuffer or NULL if error 1005 */ 1006PUBLIC XMesaBuffer 1007XMesaCreateWindowBuffer(XMesaVisual v, XMesaWindow w) 1008{ 1009 XWindowAttributes attr; 1010 XMesaBuffer b; 1011 XMesaColormap cmap; 1012 int depth; 1013 1014 assert(v); 1015 assert(w); 1016 1017 /* Check that window depth matches visual depth */ 1018 XGetWindowAttributes( v->display, w, &attr ); 1019 depth = attr.depth; 1020 if (GET_VISUAL_DEPTH(v) != depth) { 1021 _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n", 1022 GET_VISUAL_DEPTH(v), depth); 1023 return NULL; 1024 } 1025 1026 /* Find colormap */ 1027 if (attr.colormap) { 1028 cmap = attr.colormap; 1029 } 1030 else { 1031 _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w); 1032 /* this is weird, a window w/out a colormap!? */ 1033 /* OK, let's just allocate a new one and hope for the best */ 1034 cmap = XCreateColormap(v->display, w, attr.visual, AllocNone); 1035 } 1036 1037 b = create_xmesa_buffer((XMesaDrawable) w, WINDOW, v, cmap); 1038 if (!b) 1039 return NULL; 1040 1041 if (!initialize_visual_and_buffer( v, b, (XMesaDrawable) w, cmap )) { 1042 xmesa_free_buffer(b); 1043 return NULL; 1044 } 1045 1046 return b; 1047} 1048 1049 1050 1051/** 1052 * Create a new XMesaBuffer from an X pixmap. 1053 * 1054 * \param v the XMesaVisual 1055 * \param p the pixmap 1056 * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or 1057 * \c GLX_DIRECT_COLOR visual for the pixmap 1058 * \returns new XMesaBuffer or NULL if error 1059 */ 1060PUBLIC XMesaBuffer 1061XMesaCreatePixmapBuffer(XMesaVisual v, XMesaPixmap p, XMesaColormap cmap) 1062{ 1063 XMesaBuffer b; 1064 1065 assert(v); 1066 1067 b = create_xmesa_buffer((XMesaDrawable) p, PIXMAP, v, cmap); 1068 if (!b) 1069 return NULL; 1070 1071 if (!initialize_visual_and_buffer(v, b, (XMesaDrawable) p, cmap)) { 1072 xmesa_free_buffer(b); 1073 return NULL; 1074 } 1075 1076 return b; 1077} 1078 1079 1080/** 1081 * For GLX_EXT_texture_from_pixmap 1082 */ 1083XMesaBuffer 1084XMesaCreatePixmapTextureBuffer(XMesaVisual v, XMesaPixmap p, 1085 XMesaColormap cmap, 1086 int format, int target, int mipmap) 1087{ 1088 GET_CURRENT_CONTEXT(ctx); 1089 XMesaBuffer b; 1090 GLuint width, height; 1091 1092 assert(v); 1093 1094 b = create_xmesa_buffer((XMesaDrawable) p, PIXMAP, v, cmap); 1095 if (!b) 1096 return NULL; 1097 1098 /* get pixmap size, update framebuffer/renderbuffer dims */ 1099 xmesa_get_window_size(v->display, b, &width, &height); 1100 _mesa_resize_framebuffer(NULL, &(b->mesa_buffer), width, height); 1101 1102 if (target == 0) { 1103 /* examine dims */ 1104 if (ctx->Extensions.ARB_texture_non_power_of_two) { 1105 target = GLX_TEXTURE_2D_EXT; 1106 } 1107 else if ( _mesa_bitcount(width) == 1 1108 && _mesa_bitcount(height) == 1) { 1109 /* power of two size */ 1110 if (height == 1) { 1111 target = GLX_TEXTURE_1D_EXT; 1112 } 1113 else { 1114 target = GLX_TEXTURE_2D_EXT; 1115 } 1116 } 1117 else if (ctx->Extensions.NV_texture_rectangle) { 1118 target = GLX_TEXTURE_RECTANGLE_EXT; 1119 } 1120 else { 1121 /* non power of two textures not supported */ 1122 XMesaDestroyBuffer(b); 1123 return 0; 1124 } 1125 } 1126 1127 b->TextureTarget = target; 1128 b->TextureFormat = format; 1129 b->TextureMipmap = mipmap; 1130 1131 if (!initialize_visual_and_buffer(v, b, (XMesaDrawable) p, cmap)) { 1132 xmesa_free_buffer(b); 1133 return NULL; 1134 } 1135 1136 return b; 1137} 1138 1139 1140 1141XMesaBuffer 1142XMesaCreatePBuffer(XMesaVisual v, XMesaColormap cmap, 1143 unsigned int width, unsigned int height) 1144{ 1145 XMesaWindow root; 1146 XMesaDrawable drawable; /* X Pixmap Drawable */ 1147 XMesaBuffer b; 1148 1149 /* allocate pixmap for front buffer */ 1150 root = RootWindow( v->display, v->visinfo->screen ); 1151 drawable = XCreatePixmap(v->display, root, width, height, 1152 v->visinfo->depth); 1153 if (!drawable) 1154 return NULL; 1155 1156 b = create_xmesa_buffer(drawable, PBUFFER, v, cmap); 1157 if (!b) 1158 return NULL; 1159 1160 if (!initialize_visual_and_buffer(v, b, drawable, cmap)) { 1161 xmesa_free_buffer(b); 1162 return NULL; 1163 } 1164 1165 return b; 1166} 1167 1168 1169 1170/* 1171 * Deallocate an XMesaBuffer structure and all related info. 1172 */ 1173PUBLIC void 1174XMesaDestroyBuffer(XMesaBuffer b) 1175{ 1176 xmesa_free_buffer(b); 1177} 1178 1179 1180/** 1181 * Query the current window size and update the corresponding struct gl_framebuffer 1182 * and all attached renderbuffers. 1183 * Called when: 1184 * 1. the first time a buffer is bound to a context. 1185 * 2. from glViewport to poll for window size changes 1186 * 3. from the XMesaResizeBuffers() API function. 1187 * Note: it's possible (and legal) for xmctx to be NULL. That can happen 1188 * when resizing a buffer when no rendering context is bound. 1189 */ 1190void 1191xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer) 1192{ 1193 GLuint width, height; 1194 xmesa_get_window_size(drawBuffer->display, drawBuffer, &width, &height); 1195 if (drawBuffer->mesa_buffer.Width != width || 1196 drawBuffer->mesa_buffer.Height != height) { 1197 struct gl_context *ctx = xmctx ? &xmctx->mesa : NULL; 1198 _mesa_resize_framebuffer(ctx, &(drawBuffer->mesa_buffer), width, height); 1199 } 1200 drawBuffer->mesa_buffer.Initialized = GL_TRUE; /* XXX TEMPORARY? */ 1201} 1202 1203 1204/* 1205 * Bind buffer b to context c and make c the current rendering context. 1206 */ 1207GLboolean XMesaMakeCurrent( XMesaContext c, XMesaBuffer b ) 1208{ 1209 return XMesaMakeCurrent2( c, b, b ); 1210} 1211 1212 1213/* 1214 * Bind buffer b to context c and make c the current rendering context. 1215 */ 1216PUBLIC 1217GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer, 1218 XMesaBuffer readBuffer ) 1219{ 1220 if (c) { 1221 if (!drawBuffer || !readBuffer) 1222 return GL_FALSE; /* must specify buffers! */ 1223 1224 if (&(c->mesa) == _mesa_get_current_context() 1225 && c->mesa.DrawBuffer == &drawBuffer->mesa_buffer 1226 && c->mesa.ReadBuffer == &readBuffer->mesa_buffer 1227 && XMESA_BUFFER(c->mesa.DrawBuffer)->wasCurrent) { 1228 /* same context and buffer, do nothing */ 1229 return GL_TRUE; 1230 } 1231 1232 c->xm_buffer = drawBuffer; 1233 1234 /* Call this periodically to detect when the user has begun using 1235 * GL rendering from multiple threads. 1236 */ 1237 _glapi_check_multithread(); 1238 1239 xmesa_check_and_update_buffer_size(c, drawBuffer); 1240 if (readBuffer != drawBuffer) 1241 xmesa_check_and_update_buffer_size(c, readBuffer); 1242 1243 _mesa_make_current(&(c->mesa), 1244 &drawBuffer->mesa_buffer, 1245 &readBuffer->mesa_buffer); 1246 1247 /* 1248 * Must recompute and set these pixel values because colormap 1249 * can be different for different windows. 1250 */ 1251 c->clearpixel = xmesa_color_to_pixel( &c->mesa, 1252 c->clearcolor[0], 1253 c->clearcolor[1], 1254 c->clearcolor[2], 1255 c->clearcolor[3], 1256 c->xm_visual->undithered_pf); 1257 XMesaSetForeground(c->display, drawBuffer->cleargc, c->clearpixel); 1258 1259 /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */ 1260 drawBuffer->wasCurrent = GL_TRUE; 1261 } 1262 else { 1263 /* Detach */ 1264 _mesa_make_current( NULL, NULL, NULL ); 1265 } 1266 return GL_TRUE; 1267} 1268 1269 1270/* 1271 * Unbind the context c from its buffer. 1272 */ 1273GLboolean XMesaUnbindContext( XMesaContext c ) 1274{ 1275 /* A no-op for XFree86 integration purposes */ 1276 return GL_TRUE; 1277} 1278 1279 1280XMesaContext XMesaGetCurrentContext( void ) 1281{ 1282 GET_CURRENT_CONTEXT(ctx); 1283 if (ctx) { 1284 XMesaContext xmesa = XMESA_CONTEXT(ctx); 1285 return xmesa; 1286 } 1287 else { 1288 return 0; 1289 } 1290} 1291 1292 1293XMesaBuffer XMesaGetCurrentBuffer( void ) 1294{ 1295 GET_CURRENT_CONTEXT(ctx); 1296 if (ctx) { 1297 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 1298 return xmbuf; 1299 } 1300 else { 1301 return 0; 1302 } 1303} 1304 1305 1306/* New in Mesa 3.1 */ 1307XMesaBuffer XMesaGetCurrentReadBuffer( void ) 1308{ 1309 GET_CURRENT_CONTEXT(ctx); 1310 if (ctx) { 1311 return XMESA_BUFFER(ctx->ReadBuffer); 1312 } 1313 else { 1314 return 0; 1315 } 1316} 1317 1318 1319 1320GLboolean XMesaSetFXmode( GLint mode ) 1321{ 1322 (void) mode; 1323 return GL_FALSE; 1324} 1325 1326 1327 1328/* 1329 * Copy the back buffer to the front buffer. If there's no back buffer 1330 * this is a no-op. 1331 */ 1332PUBLIC 1333void XMesaSwapBuffers( XMesaBuffer b ) 1334{ 1335 GET_CURRENT_CONTEXT(ctx); 1336 1337 if (!b->backxrb) { 1338 /* single buffered */ 1339 return; 1340 } 1341 1342 /* If we're swapping the buffer associated with the current context 1343 * we have to flush any pending rendering commands first. 1344 */ 1345 if (ctx && ctx->DrawBuffer == &(b->mesa_buffer)) 1346 _mesa_notifySwapBuffers(ctx); 1347 1348 if (b->db_mode) { 1349 if (b->backxrb->ximage) { 1350 /* Copy Ximage (back buf) from client memory to server window */ 1351#if defined(USE_XSHM) 1352 if (b->shm) { 1353 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/ 1354 XShmPutImage( b->xm_visual->display, b->frontxrb->drawable, 1355 b->swapgc, 1356 b->backxrb->ximage, 0, 0, 1357 0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height, 1358 False ); 1359 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/ 1360 } 1361 else 1362#endif 1363 { 1364 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/ 1365 XMesaPutImage( b->xm_visual->display, b->frontxrb->drawable, 1366 b->swapgc, 1367 b->backxrb->ximage, 0, 0, 1368 0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height ); 1369 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/ 1370 } 1371 } 1372 else if (b->backxrb->pixmap) { 1373 /* Copy pixmap (back buf) to window (front buf) on server */ 1374 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/ 1375 XMesaCopyArea( b->xm_visual->display, 1376 b->backxrb->pixmap, /* source drawable */ 1377 b->frontxrb->drawable, /* dest. drawable */ 1378 b->swapgc, 1379 0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height, 1380 0, 0 /* dest region */ 1381 ); 1382 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/ 1383 } 1384 } 1385 XSync( b->xm_visual->display, False ); 1386} 1387 1388 1389 1390/* 1391 * Copy sub-region of back buffer to front buffer 1392 */ 1393void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height ) 1394{ 1395 GET_CURRENT_CONTEXT(ctx); 1396 1397 /* If we're swapping the buffer associated with the current context 1398 * we have to flush any pending rendering commands first. 1399 */ 1400 if (ctx && ctx->DrawBuffer == &(b->mesa_buffer)) 1401 _mesa_notifySwapBuffers(ctx); 1402 1403 if (!b->backxrb) { 1404 /* single buffered */ 1405 return; 1406 } 1407 1408 if (b->db_mode) { 1409 int yTop = b->mesa_buffer.Height - y - height; 1410 if (b->backxrb->ximage) { 1411 /* Copy Ximage from host's memory to server's window */ 1412#if defined(USE_XSHM) 1413 if (b->shm) { 1414 /* XXX assuming width and height aren't too large! */ 1415 XShmPutImage( b->xm_visual->display, b->frontxrb->drawable, 1416 b->swapgc, 1417 b->backxrb->ximage, x, yTop, 1418 x, yTop, width, height, False ); 1419 /* wait for finished event??? */ 1420 } 1421 else 1422#endif 1423 { 1424 /* XXX assuming width and height aren't too large! */ 1425 XMesaPutImage( b->xm_visual->display, b->frontxrb->drawable, 1426 b->swapgc, 1427 b->backxrb->ximage, x, yTop, 1428 x, yTop, width, height ); 1429 } 1430 } 1431 else { 1432 /* Copy pixmap to window on server */ 1433 XMesaCopyArea( b->xm_visual->display, 1434 b->backxrb->pixmap, /* source drawable */ 1435 b->frontxrb->drawable, /* dest. drawable */ 1436 b->swapgc, 1437 x, yTop, width, height, /* source region */ 1438 x, yTop /* dest region */ 1439 ); 1440 } 1441 } 1442} 1443 1444 1445/* 1446 * Return a pointer to the XMesa backbuffer Pixmap or XImage. This function 1447 * is a way to get "under the hood" of X/Mesa so one can manipulate the 1448 * back buffer directly. 1449 * Output: pixmap - pointer to back buffer's Pixmap, or 0 1450 * ximage - pointer to back buffer's XImage, or NULL 1451 * Return: GL_TRUE = context is double buffered 1452 * GL_FALSE = context is single buffered 1453 */ 1454GLboolean XMesaGetBackBuffer( XMesaBuffer b, 1455 XMesaPixmap *pixmap, 1456 XMesaImage **ximage ) 1457{ 1458 if (b->db_mode) { 1459 if (pixmap) 1460 *pixmap = b->backxrb->pixmap; 1461 if (ximage) 1462 *ximage = b->backxrb->ximage; 1463 return GL_TRUE; 1464 } 1465 else { 1466 *pixmap = 0; 1467 *ximage = NULL; 1468 return GL_FALSE; 1469 } 1470} 1471 1472 1473/* 1474 * Return the depth buffer associated with an XMesaBuffer. 1475 * Input: b - the XMesa buffer handle 1476 * Output: width, height - size of buffer in pixels 1477 * bytesPerValue - bytes per depth value (2 or 4) 1478 * buffer - pointer to depth buffer values 1479 * Return: GL_TRUE or GL_FALSE to indicate success or failure. 1480 */ 1481GLboolean XMesaGetDepthBuffer( XMesaBuffer b, GLint *width, GLint *height, 1482 GLint *bytesPerValue, void **buffer ) 1483{ 1484 struct gl_renderbuffer *rb 1485 = b->mesa_buffer.Attachment[BUFFER_DEPTH].Renderbuffer; 1486 if (!rb || !rb->Data) { 1487 *width = 0; 1488 *height = 0; 1489 *bytesPerValue = 0; 1490 *buffer = 0; 1491 return GL_FALSE; 1492 } 1493 else { 1494 *width = b->mesa_buffer.Width; 1495 *height = b->mesa_buffer.Height; 1496 *bytesPerValue = b->mesa_buffer.Visual.depthBits <= 16 1497 ? sizeof(GLushort) : sizeof(GLuint); 1498 *buffer = rb->Data; 1499 return GL_TRUE; 1500 } 1501} 1502 1503 1504void XMesaFlush( XMesaContext c ) 1505{ 1506 if (c && c->xm_visual) { 1507 XSync( c->xm_visual->display, False ); 1508 } 1509} 1510 1511 1512 1513const char *XMesaGetString( XMesaContext c, int name ) 1514{ 1515 (void) c; 1516 if (name==XMESA_VERSION) { 1517 return "5.0"; 1518 } 1519 else if (name==XMESA_EXTENSIONS) { 1520 return ""; 1521 } 1522 else { 1523 return NULL; 1524 } 1525} 1526 1527 1528 1529XMesaBuffer XMesaFindBuffer( XMesaDisplay *dpy, XMesaDrawable d ) 1530{ 1531 XMesaBuffer b; 1532 for (b=XMesaBufferList; b; b=b->Next) { 1533 if (b->frontxrb->drawable == d && b->display == dpy) { 1534 return b; 1535 } 1536 } 1537 return NULL; 1538} 1539 1540 1541/** 1542 * Free/destroy all XMesaBuffers associated with given display. 1543 */ 1544void xmesa_destroy_buffers_on_display(XMesaDisplay *dpy) 1545{ 1546 XMesaBuffer b, next; 1547 for (b = XMesaBufferList; b; b = next) { 1548 next = b->Next; 1549 if (b->display == dpy) { 1550 xmesa_free_buffer(b); 1551 } 1552 } 1553} 1554 1555 1556/* 1557 * Look for XMesaBuffers whose X window has been destroyed. 1558 * Deallocate any such XMesaBuffers. 1559 */ 1560void XMesaGarbageCollect( XMesaDisplay* dpy ) 1561{ 1562 XMesaBuffer b, next; 1563 for (b=XMesaBufferList; b; b=next) { 1564 next = b->Next; 1565 if (b->display && b->display == dpy && b->frontxrb->drawable && b->type == WINDOW) { 1566 XSync(b->display, False); 1567 if (!window_exists( b->display, b->frontxrb->drawable )) { 1568 /* found a dead window, free the ancillary info */ 1569 XMesaDestroyBuffer( b ); 1570 } 1571 } 1572 } 1573} 1574 1575 1576unsigned long XMesaDitherColor( XMesaContext xmesa, GLint x, GLint y, 1577 GLfloat red, GLfloat green, 1578 GLfloat blue, GLfloat alpha ) 1579{ 1580 GLint r = (GLint) (red * 255.0F); 1581 GLint g = (GLint) (green * 255.0F); 1582 GLint b = (GLint) (blue * 255.0F); 1583 GLint a = (GLint) (alpha * 255.0F); 1584 1585 switch (xmesa->pixelformat) { 1586 case PF_Truecolor: 1587 { 1588 unsigned long p; 1589 PACK_TRUECOLOR( p, r, g, b ); 1590 return p; 1591 } 1592 case PF_8A8B8G8R: 1593 return PACK_8A8B8G8R( r, g, b, a ); 1594 case PF_8A8R8G8B: 1595 return PACK_8A8R8G8B( r, g, b, a ); 1596 case PF_8R8G8B: 1597 return PACK_8R8G8B( r, g, b ); 1598 case PF_5R6G5B: 1599 return PACK_5R6G5B( r, g, b ); 1600 case PF_Dither_5R6G5B: 1601 /* fall through */ 1602 case PF_Dither_True: 1603 { 1604 unsigned long p; 1605 PACK_TRUEDITHER(p, x, y, r, g, b); 1606 return p; 1607 } 1608 default: 1609 _mesa_problem(NULL, "Bad pixel format in XMesaDitherColor"); 1610 } 1611 return 0; 1612} 1613 1614 1615/* 1616 * This is typically called when the window size changes and we need 1617 * to reallocate the buffer's back/depth/stencil/accum buffers. 1618 */ 1619PUBLIC void 1620XMesaResizeBuffers( XMesaBuffer b ) 1621{ 1622 GET_CURRENT_CONTEXT(ctx); 1623 XMesaContext xmctx = XMESA_CONTEXT(ctx); 1624 if (!xmctx) 1625 return; 1626 xmesa_check_and_update_buffer_size(xmctx, b); 1627} 1628 1629 1630static GLint 1631xbuffer_to_renderbuffer(int buffer) 1632{ 1633 assert(MAX_AUX_BUFFERS <= 4); 1634 1635 switch (buffer) { 1636 case GLX_FRONT_LEFT_EXT: 1637 return BUFFER_FRONT_LEFT; 1638 case GLX_FRONT_RIGHT_EXT: 1639 return BUFFER_FRONT_RIGHT; 1640 case GLX_BACK_LEFT_EXT: 1641 return BUFFER_BACK_LEFT; 1642 case GLX_BACK_RIGHT_EXT: 1643 return BUFFER_BACK_RIGHT; 1644 case GLX_AUX0_EXT: 1645 return BUFFER_AUX0; 1646 case GLX_AUX1_EXT: 1647 case GLX_AUX2_EXT: 1648 case GLX_AUX3_EXT: 1649 case GLX_AUX4_EXT: 1650 case GLX_AUX5_EXT: 1651 case GLX_AUX6_EXT: 1652 case GLX_AUX7_EXT: 1653 case GLX_AUX8_EXT: 1654 case GLX_AUX9_EXT: 1655 default: 1656 /* BadValue error */ 1657 return -1; 1658 } 1659} 1660 1661 1662PUBLIC void 1663XMesaBindTexImage(XMesaDisplay *dpy, XMesaBuffer drawable, int buffer, 1664 const int *attrib_list) 1665{ 1666#if 0 1667 GET_CURRENT_CONTEXT(ctx); 1668 const GLuint unit = ctx->Texture.CurrentUnit; 1669 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 1670 struct gl_texture_object *texObj; 1671#endif 1672 struct gl_renderbuffer *rb; 1673 struct xmesa_renderbuffer *xrb; 1674 GLint b; 1675 XMesaImage *img = NULL; 1676 GLboolean freeImg = GL_FALSE; 1677 1678 b = xbuffer_to_renderbuffer(buffer); 1679 if (b < 0) 1680 return; 1681 1682 if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_NONE_EXT) 1683 return; /* BadMatch error */ 1684 1685 rb = drawable->mesa_buffer.Attachment[b].Renderbuffer; 1686 if (!rb) { 1687 /* invalid buffer */ 1688 return; 1689 } 1690 xrb = xmesa_renderbuffer(rb); 1691 1692#if 0 1693 switch (drawable->TextureTarget) { 1694 case GLX_TEXTURE_1D_EXT: 1695 texObj = texUnit->CurrentTex[TEXTURE_1D_INDEX]; 1696 break; 1697 case GLX_TEXTURE_2D_EXT: 1698 texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX]; 1699 break; 1700 case GLX_TEXTURE_RECTANGLE_EXT: 1701 texObj = texUnit->CurrentTex[TEXTURE_RECT_INDEX]; 1702 break; 1703 default: 1704 return; /* BadMatch error */ 1705 } 1706#endif 1707 1708 /* 1709 * The following is a quick and simple way to implement 1710 * BindTexImage. The better way is to write some new FetchTexel() 1711 * functions which would extract texels from XImages. We'd still 1712 * need to use GetImage when texturing from a Pixmap (front buffer) 1713 * but texturing from a back buffer (XImage) would avoid an image 1714 * copy. 1715 */ 1716 1717 /* get XImage */ 1718 if (xrb->pixmap) { 1719 img = XMesaGetImage(dpy, xrb->pixmap, 0, 0, rb->Width, rb->Height, ~0L, 1720 ZPixmap); 1721 freeImg = GL_TRUE; 1722 } 1723 else if (xrb->ximage) { 1724 img = xrb->ximage; 1725 } 1726 1727 /* store the XImage as a new texture image */ 1728 if (img) { 1729 GLenum format, type, intFormat; 1730 if (img->bits_per_pixel == 32) { 1731 format = GL_BGRA; 1732 type = GL_UNSIGNED_BYTE; 1733 intFormat = GL_RGBA; 1734 } 1735 else if (img->bits_per_pixel == 24) { 1736 format = GL_BGR; 1737 type = GL_UNSIGNED_BYTE; 1738 intFormat = GL_RGB; 1739 } 1740 else if (img->bits_per_pixel == 16) { 1741 format = GL_BGR; 1742 type = GL_UNSIGNED_SHORT_5_6_5; 1743 intFormat = GL_RGB; 1744 } 1745 else { 1746 _mesa_problem(NULL, "Unexpected XImage format in XMesaBindTexImage"); 1747 return; 1748 } 1749 if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_RGBA_EXT) { 1750 intFormat = GL_RGBA; 1751 } 1752 else if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_RGB_EXT) { 1753 intFormat = GL_RGB; 1754 } 1755 1756 _mesa_TexImage2D(GL_TEXTURE_2D, 0, intFormat, rb->Width, rb->Height, 0, 1757 format, type, img->data); 1758 1759 if (freeImg) { 1760 XMesaDestroyImage(img); 1761 } 1762 } 1763} 1764 1765 1766 1767PUBLIC void 1768XMesaReleaseTexImage(XMesaDisplay *dpy, XMesaBuffer drawable, int buffer) 1769{ 1770 const GLint b = xbuffer_to_renderbuffer(buffer); 1771 if (b < 0) 1772 return; 1773 1774 /* no-op for now */ 1775} 1776 1777