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