xm_dd.c revision 3fa7dbf368bb060220e9f78e666b00d6827166a6
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.2 4 * 5 * Copyright (C) 1999-2006 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/** 27 * \file xm_dd.h 28 * General device driver functions for Xlib driver. 29 */ 30 31#include "glxheader.h" 32#include "main/bufferobj.h" 33#include "main/buffers.h" 34#include "main/context.h" 35#include "main/colormac.h" 36#include "main/depth.h" 37#include "main/drawpix.h" 38#include "main/extensions.h" 39#include "main/framebuffer.h" 40#include "main/macros.h" 41#include "main/image.h" 42#include "main/imports.h" 43#include "main/mtypes.h" 44#include "main/state.h" 45#include "main/texobj.h" 46#include "main/teximage.h" 47#include "main/texstore.h" 48#include "main/texformat.h" 49#include "swrast/swrast.h" 50#include "swrast/s_context.h" 51#include "swrast_setup/swrast_setup.h" 52#include "tnl/tnl.h" 53#include "tnl/t_context.h" 54#include "drivers/common/meta.h" 55#include "xmesaP.h" 56 57 58 59/* 60 * Dithering kernels and lookup tables. 61 */ 62 63const int xmesa_kernel8[DITH_DY * DITH_DX] = { 64 0 * MAXC, 8 * MAXC, 2 * MAXC, 10 * MAXC, 65 12 * MAXC, 4 * MAXC, 14 * MAXC, 6 * MAXC, 66 3 * MAXC, 11 * MAXC, 1 * MAXC, 9 * MAXC, 67 15 * MAXC, 7 * MAXC, 13 * MAXC, 5 * MAXC, 68}; 69 70const short xmesa_HPCR_DRGB[3][2][16] = { 71 { 72 { 16, -4, 1,-11, 14, -6, 3, -9, 15, -5, 2,-10, 13, -7, 4, -8}, 73 {-15, 5, 0, 12,-13, 7, -2, 10,-14, 6, -1, 11,-12, 8, -3, 9} 74 }, 75 { 76 {-11, 15, -7, 3, -8, 14, -4, 2,-10, 16, -6, 4, -9, 13, -5, 1}, 77 { 12,-14, 8, -2, 9,-13, 5, -1, 11,-15, 7, -3, 10,-12, 6, 0} 78 }, 79 { 80 { 6,-18, 26,-14, 2,-22, 30,-10, 8,-16, 28,-12, 4,-20, 32, -8}, 81 { -4, 20,-24, 16, 0, 24,-28, 12, -6, 18,-26, 14, -2, 22,-30, 10} 82 } 83}; 84 85const int xmesa_kernel1[16] = { 86 0*47, 9*47, 4*47, 12*47, /* 47 = (255*3)/16 */ 87 6*47, 2*47, 14*47, 8*47, 88 10*47, 1*47, 5*47, 11*47, 89 7*47, 13*47, 3*47, 15*47 90}; 91 92 93static void 94finish_or_flush( GLcontext *ctx ) 95{ 96#ifdef XFree86Server 97 /* NOT_NEEDED */ 98#else 99 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 100 if (xmesa) { 101 _glthread_LOCK_MUTEX(_xmesa_lock); 102 XSync( xmesa->display, False ); 103 _glthread_UNLOCK_MUTEX(_xmesa_lock); 104 } 105#endif 106} 107 108 109static void 110clear_index( GLcontext *ctx, GLuint index ) 111{ 112 if (ctx->DrawBuffer->Name == 0) { 113 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 114 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 115 xmesa->clearpixel = (unsigned long) index; 116 XMesaSetForeground( xmesa->display, xmbuf->cleargc, (unsigned long) index ); 117 } 118} 119 120 121static void 122clear_color( GLcontext *ctx, const GLfloat color[4] ) 123{ 124 if (ctx->DrawBuffer->Name == 0) { 125 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 126 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 127 128 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]); 129 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]); 130 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]); 131 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]); 132 xmesa->clearpixel = xmesa_color_to_pixel( ctx, 133 xmesa->clearcolor[0], 134 xmesa->clearcolor[1], 135 xmesa->clearcolor[2], 136 xmesa->clearcolor[3], 137 xmesa->xm_visual->undithered_pf ); 138 _glthread_LOCK_MUTEX(_xmesa_lock); 139 XMesaSetForeground( xmesa->display, xmbuf->cleargc, 140 xmesa->clearpixel ); 141 _glthread_UNLOCK_MUTEX(_xmesa_lock); 142 } 143} 144 145 146 147/* Set index mask ala glIndexMask */ 148static void 149index_mask( GLcontext *ctx, GLuint mask ) 150{ 151 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 152 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 153 /* not sure this conditional is really needed */ 154 if (xmbuf->backxrb && xmbuf->backxrb->pixmap) { 155 unsigned long m; 156 if (mask==0xffffffff) { 157 m = ((unsigned long)~0L); 158 } 159 else { 160 m = (unsigned long) mask; 161 } 162 XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m ); 163 } 164} 165 166 167/* Implements glColorMask() */ 168static void 169color_mask(GLcontext *ctx, 170 GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask) 171{ 172 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 173 XMesaBuffer xmbuf; 174 const int xclass = xmesa->xm_visual->mesa_visual.visualType; 175 (void) amask; 176 177 if (ctx->DrawBuffer->Name != 0) 178 return; 179 180 xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 181 182 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { 183 unsigned long m; 184 if (rmask && gmask && bmask) { 185 m = ((unsigned long)~0L); 186 } 187 else { 188 m = 0; 189 if (rmask) m |= GET_REDMASK(xmesa->xm_visual); 190 if (gmask) m |= GET_GREENMASK(xmesa->xm_visual); 191 if (bmask) m |= GET_BLUEMASK(xmesa->xm_visual); 192 } 193 XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m ); 194 } 195} 196 197 198 199/**********************************************************************/ 200/*** glClear implementations ***/ 201/**********************************************************************/ 202 203 204/** 205 * Clear the front or back color buffer, if it's implemented with a pixmap. 206 */ 207static void 208clear_pixmap(GLcontext *ctx, struct xmesa_renderbuffer *xrb, 209 GLint x, GLint y, GLint width, GLint height) 210{ 211 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 212 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 213 214 assert(xmbuf); 215 assert(xrb->pixmap); 216 assert(xmesa); 217 assert(xmesa->display); 218 assert(xrb->pixmap); 219 assert(xmbuf->cleargc); 220 221 XMesaFillRectangle( xmesa->display, xrb->pixmap, xmbuf->cleargc, 222 x, xrb->Base.Height - y - height, 223 width, height ); 224} 225 226 227static void 228clear_8bit_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb, 229 GLint x, GLint y, GLint width, GLint height ) 230{ 231 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 232 GLint i; 233 for (i = 0; i < height; i++) { 234 GLubyte *ptr = PIXEL_ADDR1(xrb, x, y + i); 235 MEMSET( ptr, xmesa->clearpixel, width ); 236 } 237} 238 239 240static void 241clear_HPCR_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb, 242 GLint x, GLint y, GLint width, GLint height ) 243{ 244 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 245 GLint i; 246 for (i = y; i < y + height; i++) { 247 GLubyte *ptr = PIXEL_ADDR1( xrb, x, i ); 248 int j; 249 const GLubyte *sptr = xmesa->xm_visual->hpcr_clear_ximage_pattern[0]; 250 if (i & 1) { 251 sptr += 16; 252 } 253 for (j = x; j < x + width; j++) { 254 *ptr = sptr[j&15]; 255 ptr++; 256 } 257 } 258} 259 260 261static void 262clear_16bit_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb, 263 GLint x, GLint y, GLint width, GLint height) 264{ 265 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 266 GLuint pixel = (GLuint) xmesa->clearpixel; 267 GLint i, j; 268 269 if (xmesa->swapbytes) { 270 pixel = ((pixel >> 8) & 0x00ff) | ((pixel << 8) & 0xff00); 271 } 272 273 for (j = 0; j < height; j++) { 274 GLushort *ptr2 = PIXEL_ADDR2(xrb, x, y + j); 275 for (i = 0; i < width; i++) { 276 ptr2[i] = pixel; 277 } 278 } 279} 280 281 282/* Optimized code provided by Nozomi Ytow <noz@xfree86.org> */ 283static void 284clear_24bit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb, 285 GLint x, GLint y, GLint width, GLint height) 286{ 287 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 288 const GLubyte r = xmesa->clearcolor[0]; 289 const GLubyte g = xmesa->clearcolor[1]; 290 const GLubyte b = xmesa->clearcolor[2]; 291 292 if (r == g && g == b) { 293 /* same value for all three components (gray) */ 294 GLint j; 295 for (j = 0; j < height; j++) { 296 bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j); 297 MEMSET(ptr3, r, 3 * width); 298 } 299 } 300 else { 301 /* non-gray clear color */ 302 GLint i, j; 303 for (j = 0; j < height; j++) { 304 bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j); 305 for (i = 0; i < width; i++) { 306 ptr3->r = r; 307 ptr3->g = g; 308 ptr3->b = b; 309 ptr3++; 310 } 311 } 312 } 313} 314 315 316static void 317clear_32bit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb, 318 GLint x, GLint y, GLint width, GLint height) 319{ 320 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 321 register GLuint pixel = (GLuint) xmesa->clearpixel; 322 323 if (!xrb->ximage) 324 return; 325 326 if (xmesa->swapbytes) { 327 pixel = ((pixel >> 24) & 0x000000ff) 328 | ((pixel >> 8) & 0x0000ff00) 329 | ((pixel << 8) & 0x00ff0000) 330 | ((pixel << 24) & 0xff000000); 331 } 332 333 if (width == xrb->Base.Width && height == xrb->Base.Height) { 334 /* clearing whole buffer */ 335 const GLuint n = xrb->Base.Width * xrb->Base.Height; 336 GLuint *ptr4 = (GLuint *) xrb->ximage->data; 337 if (pixel == 0) { 338 /* common case */ 339 _mesa_memset(ptr4, pixel, 4 * n); 340 } 341 else { 342 GLuint i; 343 for (i = 0; i < n; i++) 344 ptr4[i] = pixel; 345 } 346 } 347 else { 348 /* clearing scissored region */ 349 GLint i, j; 350 for (j = 0; j < height; j++) { 351 GLuint *ptr4 = PIXEL_ADDR4(xrb, x, y + j); 352 for (i = 0; i < width; i++) { 353 ptr4[i] = pixel; 354 } 355 } 356 } 357} 358 359 360static void 361clear_nbit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb, 362 GLint x, GLint y, GLint width, GLint height) 363{ 364 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 365 XMesaImage *img = xrb->ximage; 366 GLint i, j; 367 368 /* TODO: optimize this */ 369 y = YFLIP(xrb, y); 370 for (j = 0; j < height; j++) { 371 for (i = 0; i < width; i++) { 372 XMesaPutPixel(img, x+i, y-j, xmesa->clearpixel); 373 } 374 } 375} 376 377 378 379static void 380clear_buffers(GLcontext *ctx, GLbitfield buffers) 381{ 382 if (ctx->DrawBuffer->Name == 0) { 383 /* this is a window system framebuffer */ 384 const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask; 385 XMesaBuffer b = XMESA_BUFFER(ctx->DrawBuffer); 386 const GLint x = ctx->DrawBuffer->_Xmin; 387 const GLint y = ctx->DrawBuffer->_Ymin; 388 const GLint width = ctx->DrawBuffer->_Xmax - x; 389 const GLint height = ctx->DrawBuffer->_Ymax - y; 390 391 /* we can't handle color or index masking */ 392 if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) { 393 if (buffers & BUFFER_BIT_FRONT_LEFT) { 394 /* clear front color buffer */ 395 struct gl_renderbuffer *frontRb 396 = ctx->DrawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; 397 if (b->frontxrb == xmesa_renderbuffer(frontRb)) { 398 /* renderbuffer is not wrapped - great! */ 399 b->frontxrb->clearFunc(ctx, b->frontxrb, x, y, width, height); 400 buffers &= ~BUFFER_BIT_FRONT_LEFT; 401 } 402 else { 403 /* we can't directly clear an alpha-wrapped color buffer */ 404 } 405 } 406 if (buffers & BUFFER_BIT_BACK_LEFT) { 407 /* clear back color buffer */ 408 struct gl_renderbuffer *backRb 409 = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer; 410 if (b->backxrb == xmesa_renderbuffer(backRb)) { 411 /* renderbuffer is not wrapped - great! */ 412 b->backxrb->clearFunc(ctx, b->backxrb, x, y, width, height); 413 buffers &= ~BUFFER_BIT_BACK_LEFT; 414 } 415 } 416 } 417 } 418 if (buffers) 419 _swrast_Clear(ctx, buffers); 420} 421 422 423#ifndef XFree86Server 424/* XXX these functions haven't been tested in the Xserver environment */ 425 426 427/** 428 * Check if we can do an optimized glDrawPixels into an 8R8G8B visual. 429 */ 430static GLboolean 431can_do_DrawPixels_8R8G8B(GLcontext *ctx, GLenum format, GLenum type) 432{ 433 if (format == GL_BGRA && 434 type == GL_UNSIGNED_BYTE && 435 ctx->DrawBuffer && 436 ctx->DrawBuffer->Name == 0 && 437 ctx->Pixel.ZoomX == 1.0 && /* no zooming */ 438 ctx->Pixel.ZoomY == 1.0 && 439 ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) { 440 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 441 442 if (swrast->NewState) 443 _swrast_validate_derived( ctx ); 444 445 if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ { 446 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 447 if (rb) { 448 struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb->Wrapped); 449 if (xrb && 450 xrb->pixmap && /* drawing to pixmap or window */ 451 xrb->Base.AlphaBits == 0) { 452 return GL_TRUE; 453 } 454 } 455 } 456 } 457 return GL_FALSE; 458} 459 460 461/** 462 * This function implements glDrawPixels() with an XPutImage call when 463 * drawing to the front buffer (X Window drawable). 464 * The image format must be GL_BGRA to match the PF_8R8G8B pixel format. 465 */ 466static void 467xmesa_DrawPixels_8R8G8B( GLcontext *ctx, 468 GLint x, GLint y, GLsizei width, GLsizei height, 469 GLenum format, GLenum type, 470 const struct gl_pixelstore_attrib *unpack, 471 const GLvoid *pixels ) 472{ 473 if (can_do_DrawPixels_8R8G8B(ctx, format, type)) { 474 const SWcontext *swrast = SWRAST_CONTEXT( ctx ); 475 struct gl_pixelstore_attrib clippedUnpack = *unpack; 476 int dstX = x; 477 int dstY = y; 478 int w = width; 479 int h = height; 480 481 if (swrast->NewState) 482 _swrast_validate_derived( ctx ); 483 484 if (unpack->BufferObj->Name) { 485 /* unpack from PBO */ 486 GLubyte *buf; 487 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, 488 format, type, pixels)) { 489 _mesa_error(ctx, GL_INVALID_OPERATION, 490 "glDrawPixels(invalid PBO access)"); 491 return; 492 } 493 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, 494 GL_PIXEL_UNPACK_BUFFER_EXT, 495 GL_READ_ONLY_ARB, 496 unpack->BufferObj); 497 if (!buf) { 498 /* buffer is already mapped - that's an error */ 499 _mesa_error(ctx, GL_INVALID_OPERATION, 500 "glDrawPixels(PBO is mapped)"); 501 return; 502 } 503 pixels = ADD_POINTERS(buf, pixels); 504 } 505 506 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { 507 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 508 XMesaDisplay *dpy = xmesa->xm_visual->display; 509 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 510 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 511 struct xmesa_renderbuffer *xrb 512 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped); 513 const int srcX = clippedUnpack.SkipPixels; 514 const int srcY = clippedUnpack.SkipRows; 515 const int rowLength = clippedUnpack.RowLength; 516 XMesaImage ximage; 517 518 ASSERT(xmesa->xm_visual->dithered_pf == PF_8R8G8B); 519 ASSERT(xmesa->xm_visual->undithered_pf == PF_8R8G8B); 520 ASSERT(dpy); 521 ASSERT(gc); 522 523 /* This is a little tricky since all coordinates up to now have 524 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom 525 * so we have to carefully compute the Y coordinates/addresses here. 526 */ 527 MEMSET(&ximage, 0, sizeof(XMesaImage)); 528 ximage.width = width; 529 ximage.height = height; 530 ximage.format = ZPixmap; 531 ximage.data = (char *) pixels 532 + ((srcY + h - 1) * rowLength + srcX) * 4; 533 ximage.byte_order = LSBFirst; 534 ximage.bitmap_unit = 32; 535 ximage.bitmap_bit_order = LSBFirst; 536 ximage.bitmap_pad = 32; 537 ximage.depth = 32; 538 ximage.bits_per_pixel = 32; 539 ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */ 540 /* it seems we don't need to set the ximage.red/green/blue_mask fields */ 541 /* flip Y axis for dest position */ 542 dstY = YFLIP(xrb, dstY) - h + 1; 543 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); 544 } 545 546 if (unpack->BufferObj->Name) { 547 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 548 unpack->BufferObj); 549 } 550 } 551 else { 552 /* software fallback */ 553 _swrast_DrawPixels(ctx, x, y, width, height, 554 format, type, unpack, pixels); 555 } 556} 557 558 559 560/** 561 * Check if we can do an optimized glDrawPixels into an 5R6G5B visual. 562 */ 563static GLboolean 564can_do_DrawPixels_5R6G5B(GLcontext *ctx, GLenum format, GLenum type) 565{ 566 if (format == GL_RGB && 567 type == GL_UNSIGNED_SHORT_5_6_5 && 568 !ctx->Color.DitherFlag && /* no dithering */ 569 ctx->DrawBuffer && 570 ctx->DrawBuffer->Name == 0 && 571 ctx->Pixel.ZoomX == 1.0 && /* no zooming */ 572 ctx->Pixel.ZoomY == 1.0 && 573 ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) { 574 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 575 576 if (swrast->NewState) 577 _swrast_validate_derived( ctx ); 578 579 if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ { 580 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 581 if (rb) { 582 struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb->Wrapped); 583 if (xrb && 584 xrb->pixmap && /* drawing to pixmap or window */ 585 xrb->Base.AlphaBits == 0) { 586 return GL_TRUE; 587 } 588 } 589 } 590 } 591 return GL_FALSE; 592} 593 594 595/** 596 * This function implements glDrawPixels() with an XPutImage call when 597 * drawing to the front buffer (X Window drawable). The image format 598 * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to 599 * match the PF_5R6G5B pixel format. 600 */ 601static void 602xmesa_DrawPixels_5R6G5B( GLcontext *ctx, 603 GLint x, GLint y, GLsizei width, GLsizei height, 604 GLenum format, GLenum type, 605 const struct gl_pixelstore_attrib *unpack, 606 const GLvoid *pixels ) 607{ 608 if (can_do_DrawPixels_5R6G5B(ctx, format, type)) { 609 const SWcontext *swrast = SWRAST_CONTEXT( ctx ); 610 struct gl_pixelstore_attrib clippedUnpack = *unpack; 611 int dstX = x; 612 int dstY = y; 613 int w = width; 614 int h = height; 615 616 if (swrast->NewState) 617 _swrast_validate_derived( ctx ); 618 619 if (unpack->BufferObj->Name) { 620 /* unpack from PBO */ 621 GLubyte *buf; 622 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, 623 format, type, pixels)) { 624 _mesa_error(ctx, GL_INVALID_OPERATION, 625 "glDrawPixels(invalid PBO access)"); 626 return; 627 } 628 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, 629 GL_PIXEL_UNPACK_BUFFER_EXT, 630 GL_READ_ONLY_ARB, 631 unpack->BufferObj); 632 if (!buf) { 633 /* buffer is already mapped - that's an error */ 634 _mesa_error(ctx, GL_INVALID_OPERATION, 635 "glDrawPixels(PBO is mapped)"); 636 return; 637 } 638 pixels = ADD_POINTERS(buf, pixels); 639 } 640 641 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { 642 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 643 XMesaDisplay *dpy = xmesa->xm_visual->display; 644 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 645 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 646 struct xmesa_renderbuffer *xrb 647 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped); 648 const int srcX = clippedUnpack.SkipPixels; 649 const int srcY = clippedUnpack.SkipRows; 650 const int rowLength = clippedUnpack.RowLength; 651 XMesaImage ximage; 652 653 ASSERT(xmesa->xm_visual->undithered_pf == PF_5R6G5B); 654 ASSERT(dpy); 655 ASSERT(gc); 656 657 /* This is a little tricky since all coordinates up to now have 658 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom 659 * so we have to carefully compute the Y coordinates/addresses here. 660 */ 661 MEMSET(&ximage, 0, sizeof(XMesaImage)); 662 ximage.width = width; 663 ximage.height = height; 664 ximage.format = ZPixmap; 665 ximage.data = (char *) pixels 666 + ((srcY + h - 1) * rowLength + srcX) * 2; 667 ximage.byte_order = LSBFirst; 668 ximage.bitmap_unit = 16; 669 ximage.bitmap_bit_order = LSBFirst; 670 ximage.bitmap_pad = 16; 671 ximage.depth = 16; 672 ximage.bits_per_pixel = 16; 673 ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */ 674 /* it seems we don't need to set the ximage.red/green/blue_mask fields */ 675 /* flip Y axis for dest position */ 676 dstY = YFLIP(xrb, dstY) - h + 1; 677 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); 678 } 679 680 if (unpack->BufferObj->Name) { 681 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 682 unpack->BufferObj); 683 } 684 } 685 else { 686 /* software fallback */ 687 _swrast_DrawPixels(ctx, x, y, width, height, 688 format, type, unpack, pixels); 689 } 690} 691 692 693/** 694 * Determine if we can do an optimized glCopyPixels. 695 */ 696static GLboolean 697can_do_CopyPixels(GLcontext *ctx, GLenum type) 698{ 699 if (type == GL_COLOR && 700 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */ 701 ctx->Pixel.ZoomX == 1.0 && /* no zooming */ 702 ctx->Pixel.ZoomY == 1.0 && 703 ctx->Color.DrawBuffer[0] == GL_FRONT && /* copy to front buf */ 704 ctx->Pixel.ReadBuffer == GL_FRONT && /* copy from front buf */ 705 ctx->ReadBuffer->_ColorReadBuffer && 706 ctx->DrawBuffer->_ColorDrawBuffers[0]) { 707 const SWcontext *swrast = SWRAST_CONTEXT( ctx ); 708 709 if (swrast->NewState) 710 _swrast_validate_derived( ctx ); 711 712 if ((swrast->_RasterMask & ~CLIP_BIT) == 0x0 && 713 ctx->ReadBuffer && 714 ctx->ReadBuffer->_ColorReadBuffer && 715 ctx->DrawBuffer && 716 ctx->DrawBuffer->_ColorDrawBuffers[0]) { 717 struct xmesa_renderbuffer *srcXrb 718 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer->Wrapped); 719 struct xmesa_renderbuffer *dstXrb 720 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped); 721 if (srcXrb->pixmap && dstXrb->pixmap) { 722 return GL_TRUE; 723 } 724 } 725 } 726 return GL_FALSE; 727} 728 729 730/** 731 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap) 732 * for the color buffer. Don't support zooming, pixel transfer, etc. 733 * We do support copying from one window to another, ala glXMakeCurrentRead. 734 */ 735static void 736xmesa_CopyPixels( GLcontext *ctx, 737 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 738 GLint destx, GLint desty, GLenum type ) 739{ 740 if (can_do_CopyPixels(ctx, type)) { 741 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 742 XMesaDisplay *dpy = xmesa->xm_visual->display; 743 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 744 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 745 struct xmesa_renderbuffer *srcXrb 746 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer->Wrapped); 747 struct xmesa_renderbuffer *dstXrb 748 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped); 749 750 ASSERT(dpy); 751 ASSERT(gc); 752 753 /* Note: we don't do any special clipping work here. We could, 754 * but X will do it for us. 755 */ 756 srcy = YFLIP(srcXrb, srcy) - height + 1; 757 desty = YFLIP(dstXrb, desty) - height + 1; 758 XCopyArea(dpy, srcXrb->pixmap, dstXrb->pixmap, gc, 759 srcx, srcy, width, height, destx, desty); 760 } 761 else { 762 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type ); 763 } 764} 765 766#endif /* XFree86Server */ 767 768 769 770/* 771 * Every driver should implement a GetString function in order to 772 * return a meaningful GL_RENDERER string. 773 */ 774static const GLubyte * 775get_string( GLcontext *ctx, GLenum name ) 776{ 777 (void) ctx; 778 switch (name) { 779 case GL_RENDERER: 780#ifdef XFree86Server 781 return (const GLubyte *) "Mesa GLX Indirect"; 782#else 783 return (const GLubyte *) "Mesa X11"; 784#endif 785 case GL_VENDOR: 786#ifdef XFree86Server 787 return (const GLubyte *) "Mesa project: www.mesa3d.org"; 788#else 789 return NULL; 790#endif 791 default: 792 return NULL; 793 } 794} 795 796 797/* 798 * We implement the glEnable function only because we care about 799 * dither enable/disable. 800 */ 801static void 802enable( GLcontext *ctx, GLenum pname, GLboolean state ) 803{ 804 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 805 806 switch (pname) { 807 case GL_DITHER: 808 if (state) 809 xmesa->pixelformat = xmesa->xm_visual->dithered_pf; 810 else 811 xmesa->pixelformat = xmesa->xm_visual->undithered_pf; 812 break; 813 default: 814 ; /* silence compiler warning */ 815 } 816} 817 818 819static void 820clear_color_HPCR_ximage( GLcontext *ctx, const GLfloat color[4] ) 821{ 822 int i; 823 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 824 825 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]); 826 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]); 827 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]); 828 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]); 829 830 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) { 831 /* black is black */ 832 MEMSET( xmesa->xm_visual->hpcr_clear_ximage_pattern, 0x0 , 833 sizeof(xmesa->xm_visual->hpcr_clear_ximage_pattern)); 834 } 835 else { 836 /* build clear pattern */ 837 for (i=0; i<16; i++) { 838 xmesa->xm_visual->hpcr_clear_ximage_pattern[0][i] = 839 DITHER_HPCR(i, 0, 840 xmesa->clearcolor[0], 841 xmesa->clearcolor[1], 842 xmesa->clearcolor[2]); 843 xmesa->xm_visual->hpcr_clear_ximage_pattern[1][i] = 844 DITHER_HPCR(i, 1, 845 xmesa->clearcolor[0], 846 xmesa->clearcolor[1], 847 xmesa->clearcolor[2]); 848 } 849 } 850} 851 852 853static void 854clear_color_HPCR_pixmap( GLcontext *ctx, const GLfloat color[4] ) 855{ 856 int i; 857 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 858 859 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]); 860 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]); 861 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]); 862 CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]); 863 864 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) { 865 /* black is black */ 866 for (i=0; i<16; i++) { 867 XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 0, 0); 868 XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 1, 0); 869 } 870 } 871 else { 872 for (i=0; i<16; i++) { 873 XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 0, 874 DITHER_HPCR(i, 0, 875 xmesa->clearcolor[0], 876 xmesa->clearcolor[1], 877 xmesa->clearcolor[2])); 878 XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 1, 879 DITHER_HPCR(i, 1, 880 xmesa->clearcolor[0], 881 xmesa->clearcolor[1], 882 xmesa->clearcolor[2])); 883 } 884 } 885 /* change tile pixmap content */ 886 XMesaPutImage(xmesa->display, 887 (XMesaDrawable)xmesa->xm_visual->hpcr_clear_pixmap, 888 XMESA_BUFFER(ctx->DrawBuffer)->cleargc, 889 xmesa->xm_visual->hpcr_clear_ximage, 0, 0, 0, 0, 16, 2); 890} 891 892 893/** 894 * Called when the driver should update its state, based on the new_state 895 * flags. 896 */ 897void 898xmesa_update_state( GLcontext *ctx, GLbitfield new_state ) 899{ 900 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 901 902 /* Propagate statechange information to swrast and swrast_setup 903 * modules. The X11 driver has no internal GL-dependent state. 904 */ 905 _swrast_InvalidateState( ctx, new_state ); 906 _tnl_InvalidateState( ctx, new_state ); 907 _vbo_InvalidateState( ctx, new_state ); 908 _swsetup_InvalidateState( ctx, new_state ); 909 910 if (ctx->DrawBuffer->Name != 0) 911 return; 912 913 /* 914 * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect 915 * renderbuffer span/clear funcs. 916 * Check _NEW_COLOR to detect dither enable/disable. 917 */ 918 if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) { 919 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 920 struct xmesa_renderbuffer *front_xrb, *back_xrb; 921 922 front_xrb = xmbuf->frontxrb; 923 if (front_xrb) { 924 xmesa_set_renderbuffer_funcs(front_xrb, xmesa->pixelformat, 925 xmesa->xm_visual->BitsPerPixel); 926 front_xrb->clearFunc = clear_pixmap; 927 } 928 929 back_xrb = xmbuf->backxrb; 930 if (back_xrb) { 931 xmesa_set_renderbuffer_funcs(back_xrb, xmesa->pixelformat, 932 xmesa->xm_visual->BitsPerPixel); 933 if (xmbuf->backxrb->pixmap) { 934 back_xrb->clearFunc = clear_pixmap; 935 } 936 else { 937 switch (xmesa->xm_visual->BitsPerPixel) { 938 case 8: 939 if (xmesa->xm_visual->hpcr_clear_flag) { 940 back_xrb->clearFunc = clear_HPCR_ximage; 941 } 942 else { 943 back_xrb->clearFunc = clear_8bit_ximage; 944 } 945 break; 946 case 16: 947 back_xrb->clearFunc = clear_16bit_ximage; 948 break; 949 case 24: 950 back_xrb->clearFunc = clear_24bit_ximage; 951 break; 952 case 32: 953 back_xrb->clearFunc = clear_32bit_ximage; 954 break; 955 default: 956 back_xrb->clearFunc = clear_nbit_ximage; 957 break; 958 } 959 } 960 } 961 } 962 963 if (xmesa->xm_visual->hpcr_clear_flag) { 964 /* this depends on whether we're drawing to the front or back buffer */ 965 /* XXX FIX THIS! */ 966#if 0 967 if (pixmap) { 968 ctx->Driver.ClearColor = clear_color_HPCR_pixmap; 969 } 970 else { 971 ctx->Driver.ClearColor = clear_color_HPCR_ximage; 972 } 973#else 974 (void) clear_color_HPCR_pixmap; 975 (void) clear_color_HPCR_ximage; 976#endif 977 } 978} 979 980 981 982/** 983 * Called via ctx->Driver.TestProxyTeximage(). Normally, we'd just use 984 * the _mesa_test_proxy_teximage() fallback function, but we're going to 985 * special-case the 3D texture case to allow textures up to 512x512x32 986 * texels. 987 */ 988static GLboolean 989test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, 990 GLint internalFormat, GLenum format, GLenum type, 991 GLint width, GLint height, GLint depth, GLint border) 992{ 993 if (target == GL_PROXY_TEXTURE_3D) { 994 /* special case for 3D textures */ 995 if (width * height * depth > 512 * 512 * 64 || 996 width < 2 * border || 997 (!ctx->Extensions.ARB_texture_non_power_of_two && 998 _mesa_bitcount(width - 2 * border) != 1) || 999 height < 2 * border || 1000 (!ctx->Extensions.ARB_texture_non_power_of_two && 1001 _mesa_bitcount(height - 2 * border) != 1) || 1002 depth < 2 * border || 1003 (!ctx->Extensions.ARB_texture_non_power_of_two && 1004 _mesa_bitcount(depth - 2 * border) != 1)) { 1005 /* Bad size, or too many texels */ 1006 return GL_FALSE; 1007 } 1008 return GL_TRUE; 1009 } 1010 else { 1011 /* use the fallback routine for 1D, 2D, cube and rect targets */ 1012 return _mesa_test_proxy_teximage(ctx, target, level, internalFormat, 1013 format, type, width, height, depth, 1014 border); 1015 } 1016} 1017 1018 1019/** 1020 * In SW, we don't really compress GL_COMPRESSED_RGB[A] textures! 1021 */ 1022static gl_format 1023choose_tex_format( GLcontext *ctx, GLint internalFormat, 1024 GLenum format, GLenum type ) 1025{ 1026 switch (internalFormat) { 1027 case GL_COMPRESSED_RGB_ARB: 1028 return MESA_FORMAT_RGB888; 1029 case GL_COMPRESSED_RGBA_ARB: 1030 return MESA_FORMAT_RGBA8888; 1031 default: 1032 return _mesa_choose_tex_format(ctx, internalFormat, format, type); 1033 } 1034} 1035 1036 1037/** 1038 * Called by glViewport. 1039 * This is a good time for us to poll the current X window size and adjust 1040 * our renderbuffers to match the current window size. 1041 * Remember, we have no opportunity to respond to conventional 1042 * X Resize/StructureNotify events since the X driver has no event loop. 1043 * Thus, we poll. 1044 * Note that this trick isn't fool-proof. If the application never calls 1045 * glViewport, our notion of the current window size may be incorrect. 1046 * That problem led to the GLX_MESA_resize_buffers extension. 1047 */ 1048static void 1049xmesa_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) 1050{ 1051 XMesaContext xmctx = XMESA_CONTEXT(ctx); 1052 XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer); 1053 XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer); 1054 xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf); 1055 xmesa_check_and_update_buffer_size(xmctx, xmreadbuf); 1056 (void) x; 1057 (void) y; 1058 (void) w; 1059 (void) h; 1060} 1061 1062 1063#if ENABLE_EXT_timer_query 1064 1065/* 1066 * The GL_EXT_timer_query extension is not enabled for the XServer 1067 * indirect renderer. Not sure about how/if wrapping of gettimeofday() 1068 * is done, etc. 1069 */ 1070 1071struct xmesa_query_object 1072{ 1073 struct gl_query_object Base; 1074 struct timeval StartTime; 1075}; 1076 1077 1078static struct gl_query_object * 1079xmesa_new_query_object(GLcontext *ctx, GLuint id) 1080{ 1081 struct xmesa_query_object *q = CALLOC_STRUCT(xmesa_query_object); 1082 if (q) { 1083 q->Base.Id = id; 1084 q->Base.Ready = GL_TRUE; 1085 } 1086 return &q->Base; 1087} 1088 1089 1090static void 1091xmesa_begin_query(GLcontext *ctx, struct gl_query_object *q) 1092{ 1093 if (q->Target == GL_TIME_ELAPSED_EXT) { 1094 struct xmesa_query_object *xq = (struct xmesa_query_object *) q; 1095 (void) gettimeofday(&xq->StartTime, NULL); 1096 } 1097} 1098 1099 1100/** 1101 * Return the difference between the two given times in microseconds. 1102 */ 1103#ifdef __VMS 1104#define suseconds_t unsigned int 1105#endif 1106static GLuint64EXT 1107time_diff(const struct timeval *t0, const struct timeval *t1) 1108{ 1109 GLuint64EXT seconds0 = t0->tv_sec & 0xff; /* 0 .. 255 seconds */ 1110 GLuint64EXT seconds1 = t1->tv_sec & 0xff; /* 0 .. 255 seconds */ 1111 GLuint64EXT nanosec0 = (seconds0 * 1000000 + t0->tv_usec) * 1000; 1112 GLuint64EXT nanosec1 = (seconds1 * 1000000 + t1->tv_usec) * 1000; 1113 return nanosec1 - nanosec0; 1114} 1115 1116 1117static void 1118xmesa_end_query(GLcontext *ctx, struct gl_query_object *q) 1119{ 1120 if (q->Target == GL_TIME_ELAPSED_EXT) { 1121 struct xmesa_query_object *xq = (struct xmesa_query_object *) q; 1122 struct timeval endTime; 1123 (void) gettimeofday(&endTime, NULL); 1124 /* result is in nanoseconds! */ 1125 q->Result = time_diff(&xq->StartTime, &endTime); 1126 } 1127 q->Ready = GL_TRUE; 1128} 1129 1130#endif /* ENABLE_timer_query */ 1131 1132 1133/** 1134 * Initialize the device driver function table with the functions 1135 * we implement in this driver. 1136 */ 1137void 1138xmesa_init_driver_functions( XMesaVisual xmvisual, 1139 struct dd_function_table *driver ) 1140{ 1141 driver->GetString = get_string; 1142 driver->UpdateState = xmesa_update_state; 1143 driver->GetBufferSize = NULL; /* OBSOLETE */ 1144 driver->Flush = finish_or_flush; 1145 driver->Finish = finish_or_flush; 1146 driver->ClearIndex = clear_index; 1147 driver->ClearColor = clear_color; 1148 driver->IndexMask = index_mask; 1149 driver->ColorMask = color_mask; 1150 driver->Enable = enable; 1151 driver->Viewport = xmesa_viewport; 1152 if (TEST_META_FUNCS) { 1153 driver->Clear = _mesa_meta_Clear; 1154 driver->CopyPixels = _mesa_meta_CopyPixels; 1155 driver->BlitFramebuffer = _mesa_meta_BlitFramebuffer; 1156 driver->DrawPixels = _mesa_meta_DrawPixels; 1157 driver->Bitmap = _mesa_meta_Bitmap; 1158 } 1159 else { 1160 driver->Clear = clear_buffers; 1161#ifndef XFree86Server 1162 driver->CopyPixels = xmesa_CopyPixels; 1163 if (xmvisual->undithered_pf == PF_8R8G8B && 1164 xmvisual->dithered_pf == PF_8R8G8B && 1165 xmvisual->BitsPerPixel == 32) { 1166 driver->DrawPixels = xmesa_DrawPixels_8R8G8B; 1167 } 1168 else if (xmvisual->undithered_pf == PF_5R6G5B) { 1169 driver->DrawPixels = xmesa_DrawPixels_5R6G5B; 1170 } 1171#endif 1172 } 1173 driver->TestProxyTexImage = test_proxy_teximage; 1174#if ENABLE_EXT_texure_compression_s3tc 1175 driver->ChooseTextureFormat = choose_tex_format; 1176#else 1177 (void) choose_tex_format; 1178#endif 1179 1180#if ENABLE_EXT_timer_query 1181 driver->NewQueryObject = xmesa_new_query_object; 1182 driver->BeginQuery = xmesa_begin_query; 1183 driver->EndQuery = xmesa_end_query; 1184#endif 1185} 1186 1187 1188#define XMESA_NEW_POINT (_NEW_POINT | \ 1189 _NEW_RENDERMODE | \ 1190 _SWRAST_NEW_RASTERMASK) 1191 1192#define XMESA_NEW_LINE (_NEW_LINE | \ 1193 _NEW_TEXTURE | \ 1194 _NEW_LIGHT | \ 1195 _NEW_DEPTH | \ 1196 _NEW_RENDERMODE | \ 1197 _SWRAST_NEW_RASTERMASK) 1198 1199#define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \ 1200 _NEW_TEXTURE | \ 1201 _NEW_LIGHT | \ 1202 _NEW_DEPTH | \ 1203 _NEW_RENDERMODE | \ 1204 _SWRAST_NEW_RASTERMASK) 1205 1206 1207/** 1208 * Extend the software rasterizer with our line/point/triangle 1209 * functions. 1210 * Called during context creation only. 1211 */ 1212void xmesa_register_swrast_functions( GLcontext *ctx ) 1213{ 1214 SWcontext *swrast = SWRAST_CONTEXT( ctx ); 1215 1216 swrast->choose_point = xmesa_choose_point; 1217 swrast->choose_line = xmesa_choose_line; 1218 swrast->choose_triangle = xmesa_choose_triangle; 1219 1220 /* XXX these lines have no net effect. Remove??? */ 1221 swrast->InvalidatePointMask |= XMESA_NEW_POINT; 1222 swrast->InvalidateLineMask |= XMESA_NEW_LINE; 1223 swrast->InvalidateTriangleMask |= XMESA_NEW_TRIANGLE; 1224} 1225