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