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