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