Home | History | Annotate | Download | only in x11
      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