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