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
52static void
53finish_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() */
65static void
66color_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 */
104static void
105clear_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
124static void
125clear_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@xfree86.org> */
146static void
147clear_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
179static void
180clear_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
223static void
224clear_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
242static void
243clear_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 */
303static GLboolean
304can_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 */
339static void
340xmesa_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 */
435static GLboolean
436can_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 */
473static void
474xmesa_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 */
567static GLboolean
568can_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 */
606static void
607xmesa_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 */
644static const GLubyte *
645get_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 */
663static void
664enable( 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 */
685void
686xmesa_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 */
752static void
753xmesa_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
775struct xmesa_query_object
776{
777   struct gl_query_object Base;
778   struct timeval StartTime;
779};
780
781
782static struct gl_query_object *
783xmesa_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
794static void
795xmesa_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
810static GLuint64EXT
811time_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
821static void
822xmesa_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 */
841void
842xmesa_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 */
910void 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