1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * 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 mtx_lock(&_xmesa_lock); 58 XSync( xmesa->display, False ); 59 mtx_unlock(&_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 MAP_INTERNAL); 371 if (!buf) { 372 return; /* error */ 373 } 374 pixels = ADD_POINTERS(buf, pixels); 375 } 376 377 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { 378 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 379 XMesaDisplay *dpy = xmesa->xm_visual->display; 380 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 381 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 382 struct xmesa_renderbuffer *xrb 383 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); 384 const int srcX = clippedUnpack.SkipPixels; 385 const int srcY = clippedUnpack.SkipRows; 386 const int rowLength = clippedUnpack.RowLength; 387 XMesaImage ximage; 388 389 assert(xmesa->xm_visual->dithered_pf == PF_8R8G8B); 390 assert(xmesa->xm_visual->undithered_pf == PF_8R8G8B); 391 assert(dpy); 392 assert(gc); 393 394 /* This is a little tricky since all coordinates up to now have 395 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom 396 * so we have to carefully compute the Y coordinates/addresses here. 397 */ 398 memset(&ximage, 0, sizeof(XMesaImage)); 399 ximage.width = width; 400 ximage.height = height; 401 ximage.format = ZPixmap; 402 ximage.data = (char *) pixels 403 + ((srcY + h - 1) * rowLength + srcX) * 4; 404 ximage.byte_order = LSBFirst; 405 ximage.bitmap_unit = 32; 406 ximage.bitmap_bit_order = LSBFirst; 407 ximage.bitmap_pad = 32; 408 ximage.depth = 32; 409 ximage.bits_per_pixel = 32; 410 ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */ 411 /* it seems we don't need to set the ximage.red/green/blue_mask fields */ 412 /* flip Y axis for dest position */ 413 dstY = YFLIP(xrb, dstY) - h + 1; 414 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); 415 } 416 417 if (_mesa_is_bufferobj(unpack->BufferObj)) { 418 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); 419 } 420 } 421 else { 422 /* software fallback */ 423 _swrast_DrawPixels(ctx, x, y, width, height, 424 format, type, unpack, pixels); 425 } 426 } 427 428 429 430 /** 431 * Check if we can do an optimized glDrawPixels into an 5R6G5B visual. 432 */ 433 static GLboolean 434 can_do_DrawPixels_5R6G5B(struct gl_context *ctx, GLenum format, GLenum type) 435 { 436 if (format == GL_RGB && 437 type == GL_UNSIGNED_SHORT_5_6_5 && 438 !ctx->Color.DitherFlag && /* no dithering */ 439 ctx->DrawBuffer && 440 _mesa_is_winsys_fbo(ctx->DrawBuffer) && 441 ctx->Pixel.ZoomX == 1.0 && /* no zooming */ 442 ctx->Pixel.ZoomY == 1.0 && 443 ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) { 444 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 445 446 if (swrast->NewState) 447 _swrast_validate_derived( ctx ); 448 449 if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ { 450 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 451 if (rb) { 452 struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); 453 if (xrb && 454 xrb->pixmap && /* drawing to pixmap or window */ 455 _mesa_get_format_bits(xrb->Base.Base.Format, GL_ALPHA_BITS) == 0) { 456 return GL_TRUE; 457 } 458 } 459 } 460 } 461 return GL_FALSE; 462 } 463 464 465 /** 466 * This function implements glDrawPixels() with an XPutImage call when 467 * drawing to the front buffer (X Window drawable). The image format 468 * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to 469 * match the PF_5R6G5B pixel format. 470 */ 471 static void 472 xmesa_DrawPixels_5R6G5B( struct gl_context *ctx, 473 GLint x, GLint y, GLsizei width, GLsizei height, 474 GLenum format, GLenum type, 475 const struct gl_pixelstore_attrib *unpack, 476 const GLvoid *pixels ) 477 { 478 if (can_do_DrawPixels_5R6G5B(ctx, format, type)) { 479 const SWcontext *swrast = SWRAST_CONTEXT( ctx ); 480 struct gl_pixelstore_attrib clippedUnpack = *unpack; 481 int dstX = x; 482 int dstY = y; 483 int w = width; 484 int h = height; 485 486 if (swrast->NewState) 487 _swrast_validate_derived( ctx ); 488 489 if (_mesa_is_bufferobj(unpack->BufferObj)) { 490 /* unpack from PBO */ 491 GLubyte *buf; 492 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, 493 format, type, INT_MAX, pixels)) { 494 _mesa_error(ctx, GL_INVALID_OPERATION, 495 "glDrawPixels(invalid PBO access)"); 496 return; 497 } 498 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 499 unpack->BufferObj->Size, 500 GL_MAP_READ_BIT, 501 unpack->BufferObj, 502 MAP_INTERNAL); 503 if (!buf) { 504 return; /* error */ 505 } 506 pixels = ADD_POINTERS(buf, pixels); 507 } 508 509 if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { 510 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 511 XMesaDisplay *dpy = xmesa->xm_visual->display; 512 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 513 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 514 struct xmesa_renderbuffer *xrb 515 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); 516 const int srcX = clippedUnpack.SkipPixels; 517 const int srcY = clippedUnpack.SkipRows; 518 const int rowLength = clippedUnpack.RowLength; 519 XMesaImage ximage; 520 521 assert(xmesa->xm_visual->undithered_pf == PF_5R6G5B); 522 assert(dpy); 523 assert(gc); 524 525 /* This is a little tricky since all coordinates up to now have 526 * been in the OpenGL bottom-to-top orientation. X is top-to-bottom 527 * so we have to carefully compute the Y coordinates/addresses here. 528 */ 529 memset(&ximage, 0, sizeof(XMesaImage)); 530 ximage.width = width; 531 ximage.height = height; 532 ximage.format = ZPixmap; 533 ximage.data = (char *) pixels 534 + ((srcY + h - 1) * rowLength + srcX) * 2; 535 ximage.byte_order = LSBFirst; 536 ximage.bitmap_unit = 16; 537 ximage.bitmap_bit_order = LSBFirst; 538 ximage.bitmap_pad = 16; 539 ximage.depth = 16; 540 ximage.bits_per_pixel = 16; 541 ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */ 542 /* it seems we don't need to set the ximage.red/green/blue_mask fields */ 543 /* flip Y axis for dest position */ 544 dstY = YFLIP(xrb, dstY) - h + 1; 545 XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); 546 } 547 548 if (unpack->BufferObj->Name) { 549 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); 550 } 551 } 552 else { 553 /* software fallback */ 554 _swrast_DrawPixels(ctx, x, y, width, height, 555 format, type, unpack, pixels); 556 } 557 } 558 559 560 /** 561 * Determine if we can do an optimized glCopyPixels. 562 */ 563 static GLboolean 564 can_do_CopyPixels(struct gl_context *ctx, GLenum type) 565 { 566 if (type == GL_COLOR && 567 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */ 568 ctx->Pixel.ZoomX == 1.0 && /* no zooming */ 569 ctx->Pixel.ZoomY == 1.0 && 570 ctx->Color.DrawBuffer[0] == GL_FRONT && /* copy to front buf */ 571 ctx->Pixel.ReadBuffer == GL_FRONT && /* copy from front buf */ 572 ctx->ReadBuffer->_ColorReadBuffer && 573 ctx->DrawBuffer->_ColorDrawBuffers[0]) { 574 const SWcontext *swrast = SWRAST_CONTEXT( ctx ); 575 576 if (swrast->NewState) 577 _swrast_validate_derived( ctx ); 578 579 if ((swrast->_RasterMask & ~CLIP_BIT) == 0x0 && 580 ctx->ReadBuffer && 581 ctx->ReadBuffer->_ColorReadBuffer && 582 ctx->DrawBuffer && 583 ctx->DrawBuffer->_ColorDrawBuffers[0]) { 584 struct xmesa_renderbuffer *srcXrb 585 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); 586 struct xmesa_renderbuffer *dstXrb 587 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); 588 if (srcXrb->pixmap && dstXrb->pixmap) { 589 return GL_TRUE; 590 } 591 } 592 } 593 return GL_FALSE; 594 } 595 596 597 /** 598 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap) 599 * for the color buffer. Don't support zooming, pixel transfer, etc. 600 * We do support copying from one window to another, ala glXMakeCurrentRead. 601 */ 602 static void 603 xmesa_CopyPixels( struct gl_context *ctx, 604 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 605 GLint destx, GLint desty, GLenum type ) 606 { 607 if (can_do_CopyPixels(ctx, type)) { 608 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 609 XMesaDisplay *dpy = xmesa->xm_visual->display; 610 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 611 const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ 612 struct xmesa_renderbuffer *srcXrb 613 = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); 614 struct xmesa_renderbuffer *dstXrb 615 = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); 616 617 assert(dpy); 618 assert(gc); 619 620 /* Note: we don't do any special clipping work here. We could, 621 * but X will do it for us. 622 */ 623 srcy = YFLIP(srcXrb, srcy) - height + 1; 624 desty = YFLIP(dstXrb, desty) - height + 1; 625 XCopyArea(dpy, srcXrb->pixmap, dstXrb->pixmap, gc, 626 srcx, srcy, width, height, destx, desty); 627 } 628 else { 629 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type ); 630 } 631 } 632 633 634 635 636 /* 637 * Every driver should implement a GetString function in order to 638 * return a meaningful GL_RENDERER string. 639 */ 640 static const GLubyte * 641 get_string( struct gl_context *ctx, GLenum name ) 642 { 643 (void) ctx; 644 switch (name) { 645 case GL_RENDERER: 646 return (const GLubyte *) "Mesa X11"; 647 case GL_VENDOR: 648 return NULL; 649 default: 650 return NULL; 651 } 652 } 653 654 655 /* 656 * We implement the glEnable function only because we care about 657 * dither enable/disable. 658 */ 659 static void 660 enable( struct gl_context *ctx, GLenum pname, GLboolean state ) 661 { 662 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 663 664 switch (pname) { 665 case GL_DITHER: 666 if (state) 667 xmesa->pixelformat = xmesa->xm_visual->dithered_pf; 668 else 669 xmesa->pixelformat = xmesa->xm_visual->undithered_pf; 670 break; 671 default: 672 ; /* silence compiler warning */ 673 } 674 } 675 676 677 /** 678 * Called when the driver should update its state, based on the new_state 679 * flags. 680 */ 681 void 682 xmesa_update_state( struct gl_context *ctx, GLbitfield new_state ) 683 { 684 const XMesaContext xmesa = XMESA_CONTEXT(ctx); 685 686 /* Propagate statechange information to swrast and swrast_setup 687 * modules. The X11 driver has no internal GL-dependent state. 688 */ 689 _swrast_InvalidateState( ctx, new_state ); 690 _tnl_InvalidateState( ctx, new_state ); 691 _vbo_InvalidateState( ctx, new_state ); 692 _swsetup_InvalidateState( ctx, new_state ); 693 694 if (_mesa_is_user_fbo(ctx->DrawBuffer)) 695 return; 696 697 /* 698 * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect 699 * renderbuffer span/clear funcs. 700 * Check _NEW_COLOR to detect dither enable/disable. 701 */ 702 if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) { 703 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); 704 struct xmesa_renderbuffer *front_xrb, *back_xrb; 705 706 front_xrb = xmbuf->frontxrb; 707 if (front_xrb) { 708 front_xrb->clearFunc = clear_pixmap; 709 } 710 711 back_xrb = xmbuf->backxrb; 712 if (back_xrb) { 713 if (xmbuf->backxrb->pixmap) { 714 back_xrb->clearFunc = clear_pixmap; 715 } 716 else { 717 switch (xmesa->xm_visual->BitsPerPixel) { 718 case 16: 719 back_xrb->clearFunc = clear_16bit_ximage; 720 break; 721 case 24: 722 back_xrb->clearFunc = clear_24bit_ximage; 723 break; 724 case 32: 725 back_xrb->clearFunc = clear_32bit_ximage; 726 break; 727 default: 728 back_xrb->clearFunc = clear_nbit_ximage; 729 break; 730 } 731 } 732 } 733 } 734 } 735 736 737 /** 738 * Called by glViewport. 739 * This is a good time for us to poll the current X window size and adjust 740 * our renderbuffers to match the current window size. 741 * Remember, we have no opportunity to respond to conventional 742 * X Resize/StructureNotify events since the X driver has no event loop. 743 * Thus, we poll. 744 * Note that this trick isn't fool-proof. If the application never calls 745 * glViewport, our notion of the current window size may be incorrect. 746 * That problem led to the GLX_MESA_resize_buffers extension. 747 */ 748 static void 749 xmesa_viewport(struct gl_context *ctx) 750 { 751 XMesaContext xmctx = XMESA_CONTEXT(ctx); 752 XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer); 753 XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer); 754 xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf); 755 xmesa_check_and_update_buffer_size(xmctx, xmreadbuf); 756 } 757 758 759 #if ENABLE_EXT_timer_query 760 761 /* 762 * The GL_EXT_timer_query extension is not enabled for the XServer 763 * indirect renderer. Not sure about how/if wrapping of gettimeofday() 764 * is done, etc. 765 */ 766 767 struct xmesa_query_object 768 { 769 struct gl_query_object Base; 770 struct timeval StartTime; 771 }; 772 773 774 static struct gl_query_object * 775 xmesa_new_query_object(struct gl_context *ctx, GLuint id) 776 { 777 struct xmesa_query_object *q = CALLOC_STRUCT(xmesa_query_object); 778 if (q) { 779 q->Base.Id = id; 780 q->Base.Ready = GL_TRUE; 781 } 782 return &q->Base; 783 } 784 785 786 static void 787 xmesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 788 { 789 if (q->Target == GL_TIME_ELAPSED_EXT) { 790 struct xmesa_query_object *xq = (struct xmesa_query_object *) q; 791 (void) gettimeofday(&xq->StartTime, NULL); 792 } 793 } 794 795 796 /** 797 * Return the difference between the two given times in microseconds. 798 */ 799 static GLuint64EXT 800 time_diff(const struct timeval *t0, const struct timeval *t1) 801 { 802 GLuint64EXT seconds0 = t0->tv_sec & 0xff; /* 0 .. 255 seconds */ 803 GLuint64EXT seconds1 = t1->tv_sec & 0xff; /* 0 .. 255 seconds */ 804 GLuint64EXT nanosec0 = (seconds0 * 1000000 + t0->tv_usec) * 1000; 805 GLuint64EXT nanosec1 = (seconds1 * 1000000 + t1->tv_usec) * 1000; 806 return nanosec1 - nanosec0; 807 } 808 809 810 static void 811 xmesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 812 { 813 if (q->Target == GL_TIME_ELAPSED_EXT) { 814 struct xmesa_query_object *xq = (struct xmesa_query_object *) q; 815 struct timeval endTime; 816 (void) gettimeofday(&endTime, NULL); 817 /* result is in nanoseconds! */ 818 q->Result = time_diff(&xq->StartTime, &endTime); 819 } 820 q->Ready = GL_TRUE; 821 } 822 823 #endif /* ENABLE_timer_query */ 824 825 826 /** 827 * Initialize the device driver function table with the functions 828 * we implement in this driver. 829 */ 830 void 831 xmesa_init_driver_functions( XMesaVisual xmvisual, 832 struct dd_function_table *driver ) 833 { 834 driver->GetString = get_string; 835 driver->UpdateState = xmesa_update_state; 836 driver->Flush = finish_or_flush; 837 driver->Finish = finish_or_flush; 838 driver->ColorMask = color_mask; 839 driver->Enable = enable; 840 driver->Viewport = xmesa_viewport; 841 if (TEST_META_FUNCS) { 842 driver->Clear = _mesa_meta_Clear; 843 driver->CopyPixels = _mesa_meta_CopyPixels; 844 driver->BlitFramebuffer = _mesa_meta_and_swrast_BlitFramebuffer; 845 driver->DrawPixels = _mesa_meta_DrawPixels; 846 driver->Bitmap = _mesa_meta_Bitmap; 847 } 848 else { 849 driver->Clear = clear_buffers; 850 driver->CopyPixels = xmesa_CopyPixels; 851 if (xmvisual->undithered_pf == PF_8R8G8B && 852 xmvisual->dithered_pf == PF_8R8G8B && 853 xmvisual->BitsPerPixel == 32) { 854 driver->DrawPixels = xmesa_DrawPixels_8R8G8B; 855 } 856 else if (xmvisual->undithered_pf == PF_5R6G5B) { 857 driver->DrawPixels = xmesa_DrawPixels_5R6G5B; 858 } 859 } 860 861 driver->MapRenderbuffer = xmesa_MapRenderbuffer; 862 driver->UnmapRenderbuffer = xmesa_UnmapRenderbuffer; 863 864 driver->GenerateMipmap = _mesa_generate_mipmap; 865 866 #if ENABLE_EXT_timer_query 867 driver->NewQueryObject = xmesa_new_query_object; 868 driver->BeginQuery = xmesa_begin_query; 869 driver->EndQuery = xmesa_end_query; 870 #endif 871 } 872 873 874 #define XMESA_NEW_POINT (_NEW_POINT | \ 875 _NEW_RENDERMODE | \ 876 _SWRAST_NEW_RASTERMASK) 877 878 #define XMESA_NEW_LINE (_NEW_LINE | \ 879 _NEW_TEXTURE | \ 880 _NEW_LIGHT | \ 881 _NEW_DEPTH | \ 882 _NEW_RENDERMODE | \ 883 _SWRAST_NEW_RASTERMASK) 884 885 #define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \ 886 _NEW_TEXTURE | \ 887 _NEW_LIGHT | \ 888 _NEW_DEPTH | \ 889 _NEW_RENDERMODE | \ 890 _SWRAST_NEW_RASTERMASK) 891 892 893 /** 894 * Extend the software rasterizer with our line/point/triangle 895 * functions. 896 * Called during context creation only. 897 */ 898 void xmesa_register_swrast_functions( struct gl_context *ctx ) 899 { 900 SWcontext *swrast = SWRAST_CONTEXT( ctx ); 901 902 swrast->choose_point = xmesa_choose_point; 903 swrast->choose_line = xmesa_choose_line; 904 swrast->choose_triangle = xmesa_choose_triangle; 905 906 /* XXX these lines have no net effect. Remove??? */ 907 swrast->InvalidatePointMask |= XMESA_NEW_POINT; 908 swrast->InvalidateLineMask |= XMESA_NEW_LINE; 909 swrast->InvalidateTriangleMask |= XMESA_NEW_TRIANGLE; 910 } 911