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