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