xm_dd.c revision 8126dfa9c24c972794193bf652d6d09a1d01b376
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/buffers.h"
34#include "main/context.h"
35#include "main/colormac.h"
36#include "main/depth.h"
37#include "main/drawpix.h"
38#include "main/extensions.h"
39#include "main/framebuffer.h"
40#include "main/macros.h"
41#include "main/image.h"
42#include "main/imports.h"
43#include "main/mtypes.h"
44#include "main/state.h"
45#include "main/texobj.h"
46#include "main/teximage.h"
47#include "main/texstore.h"
48#include "main/texformat.h"
49#include "swrast/swrast.h"
50#include "swrast/s_context.h"
51#include "swrast_setup/swrast_setup.h"
52#include "tnl/tnl.h"
53#include "tnl/t_context.h"
54#include "drivers/common/meta.h"
55#include "xmesaP.h"
56
57
58
59/*
60 * Dithering kernels and lookup tables.
61 */
62
63const int xmesa_kernel8[DITH_DY * DITH_DX] = {
64    0 * MAXC,  8 * MAXC,  2 * MAXC, 10 * MAXC,
65   12 * MAXC,  4 * MAXC, 14 * MAXC,  6 * MAXC,
66    3 * MAXC, 11 * MAXC,  1 * MAXC,  9 * MAXC,
67   15 * MAXC,  7 * MAXC, 13 * MAXC,  5 * MAXC,
68};
69
70const short xmesa_HPCR_DRGB[3][2][16] = {
71   {
72      { 16, -4,  1,-11, 14, -6,  3, -9, 15, -5,  2,-10, 13, -7,  4, -8},
73      {-15,  5,  0, 12,-13,  7, -2, 10,-14,  6, -1, 11,-12,  8, -3,  9}
74   },
75   {
76      {-11, 15, -7,  3, -8, 14, -4,  2,-10, 16, -6,  4, -9, 13, -5,  1},
77      { 12,-14,  8, -2,  9,-13,  5, -1, 11,-15,  7, -3, 10,-12,  6,  0}
78   },
79   {
80      {  6,-18, 26,-14,  2,-22, 30,-10,  8,-16, 28,-12,  4,-20, 32, -8},
81      { -4, 20,-24, 16,  0, 24,-28, 12, -6, 18,-26, 14, -2, 22,-30, 10}
82   }
83};
84
85const int xmesa_kernel1[16] = {
86   0*47,  9*47,  4*47, 12*47,     /* 47 = (255*3)/16 */
87   6*47,  2*47, 14*47,  8*47,
88  10*47,  1*47,  5*47, 11*47,
89   7*47, 13*47,  3*47, 15*47
90};
91
92
93static void
94finish_or_flush( GLcontext *ctx )
95{
96#ifdef XFree86Server
97      /* NOT_NEEDED */
98#else
99   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
100   if (xmesa) {
101      _glthread_LOCK_MUTEX(_xmesa_lock);
102      XSync( xmesa->display, False );
103      _glthread_UNLOCK_MUTEX(_xmesa_lock);
104   }
105#endif
106}
107
108
109static void
110clear_index( GLcontext *ctx, GLuint index )
111{
112   if (ctx->DrawBuffer->Name == 0) {
113      const XMesaContext xmesa = XMESA_CONTEXT(ctx);
114      XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
115      xmesa->clearpixel = (unsigned long) index;
116      XMesaSetForeground( xmesa->display, xmbuf->cleargc, (unsigned long) index );
117   }
118}
119
120
121static void
122clear_color( GLcontext *ctx, const GLfloat color[4] )
123{
124   if (ctx->DrawBuffer->Name == 0) {
125      const XMesaContext xmesa = XMESA_CONTEXT(ctx);
126      XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
127
128      CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]);
129      CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]);
130      CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]);
131      CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]);
132      xmesa->clearpixel = xmesa_color_to_pixel( ctx,
133                                                xmesa->clearcolor[0],
134                                                xmesa->clearcolor[1],
135                                                xmesa->clearcolor[2],
136                                                xmesa->clearcolor[3],
137                                                xmesa->xm_visual->undithered_pf );
138      _glthread_LOCK_MUTEX(_xmesa_lock);
139      XMesaSetForeground( xmesa->display, xmbuf->cleargc,
140                          xmesa->clearpixel );
141      _glthread_UNLOCK_MUTEX(_xmesa_lock);
142   }
143}
144
145
146
147/* Set index mask ala glIndexMask */
148static void
149index_mask( GLcontext *ctx, GLuint mask )
150{
151   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
152   XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
153   /* not sure this conditional is really needed */
154   if (xmbuf->backxrb && xmbuf->backxrb->pixmap) {
155      unsigned long m;
156      if (mask==0xffffffff) {
157	 m = ((unsigned long)~0L);
158      }
159      else {
160         m = (unsigned long) mask;
161      }
162      XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m );
163   }
164}
165
166
167/* Implements glColorMask() */
168static void
169color_mask(GLcontext *ctx,
170           GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask)
171{
172   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
173   XMesaBuffer xmbuf;
174   const int xclass = xmesa->xm_visual->mesa_visual.visualType;
175   (void) amask;
176
177   if (ctx->DrawBuffer->Name != 0)
178      return;
179
180   xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
181
182   if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
183      unsigned long m;
184      if (rmask && gmask && bmask) {
185         m = ((unsigned long)~0L);
186      }
187      else {
188         m = 0;
189         if (rmask)   m |= GET_REDMASK(xmesa->xm_visual);
190         if (gmask)   m |= GET_GREENMASK(xmesa->xm_visual);
191         if (bmask)   m |= GET_BLUEMASK(xmesa->xm_visual);
192      }
193      XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m );
194   }
195}
196
197
198
199/**********************************************************************/
200/*** glClear implementations                                        ***/
201/**********************************************************************/
202
203
204/**
205 * Clear the front or back color buffer, if it's implemented with a pixmap.
206 */
207static void
208clear_pixmap(GLcontext *ctx, struct xmesa_renderbuffer *xrb,
209             GLint x, GLint y, GLint width, GLint height)
210{
211   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
212   XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
213
214   assert(xmbuf);
215   assert(xrb->pixmap);
216   assert(xmesa);
217   assert(xmesa->display);
218   assert(xrb->pixmap);
219   assert(xmbuf->cleargc);
220
221   XMesaFillRectangle( xmesa->display, xrb->pixmap, xmbuf->cleargc,
222                       x, xrb->Base.Height - y - height,
223                       width, height );
224}
225
226
227static void
228clear_8bit_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb,
229                   GLint x, GLint y, GLint width, GLint height )
230{
231   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
232   GLint i;
233   for (i = 0; i < height; i++) {
234      GLubyte *ptr = PIXEL_ADDR1(xrb, x, y + i);
235      MEMSET( ptr, xmesa->clearpixel, width );
236   }
237}
238
239
240static void
241clear_HPCR_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb,
242                   GLint x, GLint y, GLint width, GLint height )
243{
244   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
245   GLint i;
246   for (i = y; i < y + height; i++) {
247      GLubyte *ptr = PIXEL_ADDR1( xrb, x, i );
248      int j;
249      const GLubyte *sptr = xmesa->xm_visual->hpcr_clear_ximage_pattern[0];
250      if (i & 1) {
251         sptr += 16;
252      }
253      for (j = x; j < x + width; j++) {
254         *ptr = sptr[j&15];
255         ptr++;
256      }
257   }
258}
259
260
261static void
262clear_16bit_ximage( GLcontext *ctx, struct xmesa_renderbuffer *xrb,
263                    GLint x, GLint y, GLint width, GLint height)
264{
265   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
266   GLuint pixel = (GLuint) xmesa->clearpixel;
267   GLint i, j;
268
269   if (xmesa->swapbytes) {
270      pixel = ((pixel >> 8) & 0x00ff) | ((pixel << 8) & 0xff00);
271   }
272
273   for (j = 0; j < height; j++) {
274      GLushort *ptr2 = PIXEL_ADDR2(xrb, x, y + j);
275      for (i = 0; i < width; i++) {
276         ptr2[i] = pixel;
277      }
278   }
279}
280
281
282/* Optimized code provided by Nozomi Ytow <noz@xfree86.org> */
283static void
284clear_24bit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb,
285                   GLint x, GLint y, GLint width, GLint height)
286{
287   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
288   const GLubyte r = xmesa->clearcolor[0];
289   const GLubyte g = xmesa->clearcolor[1];
290   const GLubyte b = xmesa->clearcolor[2];
291
292   if (r == g && g == b) {
293      /* same value for all three components (gray) */
294      GLint j;
295      for (j = 0; j < height; j++) {
296         bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j);
297         MEMSET(ptr3, r, 3 * width);
298      }
299   }
300   else {
301      /* non-gray clear color */
302      GLint i, j;
303      for (j = 0; j < height; j++) {
304         bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j);
305         for (i = 0; i < width; i++) {
306            ptr3->r = r;
307            ptr3->g = g;
308            ptr3->b = b;
309            ptr3++;
310         }
311      }
312   }
313}
314
315
316static void
317clear_32bit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb,
318                   GLint x, GLint y, GLint width, GLint height)
319{
320   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
321   register GLuint pixel = (GLuint) xmesa->clearpixel;
322
323   if (!xrb->ximage)
324      return;
325
326   if (xmesa->swapbytes) {
327      pixel = ((pixel >> 24) & 0x000000ff)
328            | ((pixel >> 8)  & 0x0000ff00)
329            | ((pixel << 8)  & 0x00ff0000)
330            | ((pixel << 24) & 0xff000000);
331   }
332
333   if (width == xrb->Base.Width && height == xrb->Base.Height) {
334      /* clearing whole buffer */
335      const GLuint n = xrb->Base.Width * xrb->Base.Height;
336      GLuint *ptr4 = (GLuint *) xrb->ximage->data;
337      if (pixel == 0) {
338         /* common case */
339         _mesa_memset(ptr4, pixel, 4 * n);
340      }
341      else {
342         GLuint i;
343         for (i = 0; i < n; i++)
344            ptr4[i] = pixel;
345      }
346   }
347   else {
348      /* clearing scissored region */
349      GLint i, j;
350      for (j = 0; j < height; j++) {
351         GLuint *ptr4 = PIXEL_ADDR4(xrb, x, y + j);
352         for (i = 0; i < width; i++) {
353            ptr4[i] = pixel;
354         }
355      }
356   }
357}
358
359
360static void
361clear_nbit_ximage(GLcontext *ctx, struct xmesa_renderbuffer *xrb,
362                  GLint x, GLint y, GLint width, GLint height)
363{
364   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
365   XMesaImage *img = xrb->ximage;
366   GLint i, j;
367
368   /* TODO: optimize this */
369   y = YFLIP(xrb, y);
370   for (j = 0; j < height; j++) {
371      for (i = 0; i < width; i++) {
372         XMesaPutPixel(img, x+i, y-j, xmesa->clearpixel);
373      }
374   }
375}
376
377
378
379static void
380clear_buffers(GLcontext *ctx, GLbitfield buffers)
381{
382   if (ctx->DrawBuffer->Name == 0) {
383      /* this is a window system framebuffer */
384      const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask;
385      XMesaBuffer b = XMESA_BUFFER(ctx->DrawBuffer);
386      const GLint x = ctx->DrawBuffer->_Xmin;
387      const GLint y = ctx->DrawBuffer->_Ymin;
388      const GLint width = ctx->DrawBuffer->_Xmax - x;
389      const GLint height = ctx->DrawBuffer->_Ymax - y;
390
391      /* we can't handle color or index masking */
392      if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) {
393         if (buffers & BUFFER_BIT_FRONT_LEFT) {
394            /* clear front color buffer */
395            struct gl_renderbuffer *frontRb
396               = ctx->DrawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
397            if (b->frontxrb == xmesa_renderbuffer(frontRb)) {
398               /* renderbuffer is not wrapped - great! */
399               b->frontxrb->clearFunc(ctx, b->frontxrb, x, y, width, height);
400               buffers &= ~BUFFER_BIT_FRONT_LEFT;
401            }
402            else {
403               /* we can't directly clear an alpha-wrapped color buffer */
404            }
405         }
406         if (buffers & BUFFER_BIT_BACK_LEFT) {
407            /* clear back color buffer */
408            struct gl_renderbuffer *backRb
409               = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
410            if (b->backxrb == xmesa_renderbuffer(backRb)) {
411               /* renderbuffer is not wrapped - great! */
412               b->backxrb->clearFunc(ctx, b->backxrb, x, y, width, height);
413               buffers &= ~BUFFER_BIT_BACK_LEFT;
414            }
415         }
416      }
417   }
418   if (buffers)
419      _swrast_Clear(ctx, buffers);
420}
421
422
423#ifndef XFree86Server
424/* XXX these functions haven't been tested in the Xserver environment */
425
426
427/**
428 * Check if we can do an optimized glDrawPixels into an 8R8G8B visual.
429 */
430static GLboolean
431can_do_DrawPixels_8R8G8B(GLcontext *ctx, GLenum format, GLenum type)
432{
433   if (format == GL_BGRA &&
434       type == GL_UNSIGNED_BYTE &&
435       ctx->DrawBuffer &&
436       ctx->DrawBuffer->Name == 0 &&
437       ctx->Pixel.ZoomX == 1.0 &&        /* no zooming */
438       ctx->Pixel.ZoomY == 1.0 &&
439       ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) {
440      const SWcontext *swrast = SWRAST_CONTEXT(ctx);
441
442      if (swrast->NewState)
443         _swrast_validate_derived( ctx );
444
445      if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ {
446         struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
447         if (rb) {
448            struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb->Wrapped);
449            if (xrb &&
450                xrb->pixmap && /* drawing to pixmap or window */
451                xrb->Base.AlphaBits == 0) {
452               return GL_TRUE;
453            }
454         }
455      }
456   }
457   return GL_FALSE;
458}
459
460
461/**
462 * This function implements glDrawPixels() with an XPutImage call when
463 * drawing to the front buffer (X Window drawable).
464 * The image format must be GL_BGRA to match the PF_8R8G8B pixel format.
465 */
466static void
467xmesa_DrawPixels_8R8G8B( GLcontext *ctx,
468                         GLint x, GLint y, GLsizei width, GLsizei height,
469                         GLenum format, GLenum type,
470                         const struct gl_pixelstore_attrib *unpack,
471                         const GLvoid *pixels )
472{
473   if (can_do_DrawPixels_8R8G8B(ctx, format, type)) {
474      const SWcontext *swrast = SWRAST_CONTEXT( ctx );
475      struct gl_pixelstore_attrib clippedUnpack = *unpack;
476      int dstX = x;
477      int dstY = y;
478      int w = width;
479      int h = height;
480
481      if (swrast->NewState)
482         _swrast_validate_derived( ctx );
483
484      if (unpack->BufferObj->Name) {
485         /* unpack from PBO */
486         GLubyte *buf;
487         if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
488                                        format, type, pixels)) {
489            _mesa_error(ctx, GL_INVALID_OPERATION,
490                        "glDrawPixels(invalid PBO access)");
491            return;
492         }
493         buf = (GLubyte *) ctx->Driver.MapBuffer(ctx,
494                                                 GL_PIXEL_UNPACK_BUFFER_EXT,
495                                                 GL_READ_ONLY_ARB,
496                                                 unpack->BufferObj);
497         if (!buf) {
498            /* buffer is already mapped - that's an error */
499            _mesa_error(ctx, GL_INVALID_OPERATION,
500                        "glDrawPixels(PBO is mapped)");
501            return;
502         }
503         pixels = ADD_POINTERS(buf, pixels);
504      }
505
506      if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) {
507         const XMesaContext xmesa = XMESA_CONTEXT(ctx);
508         XMesaDisplay *dpy = xmesa->xm_visual->display;
509         XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
510         const XMesaGC gc = xmbuf->cleargc;  /* effected by glColorMask */
511         struct xmesa_renderbuffer *xrb
512            = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped);
513         const int srcX = clippedUnpack.SkipPixels;
514         const int srcY = clippedUnpack.SkipRows;
515         const int rowLength = clippedUnpack.RowLength;
516         XMesaImage ximage;
517
518         ASSERT(xmesa->xm_visual->dithered_pf == PF_8R8G8B);
519         ASSERT(xmesa->xm_visual->undithered_pf == PF_8R8G8B);
520         ASSERT(dpy);
521         ASSERT(gc);
522
523         /* This is a little tricky since all coordinates up to now have
524          * been in the OpenGL bottom-to-top orientation.  X is top-to-bottom
525          * so we have to carefully compute the Y coordinates/addresses here.
526          */
527         MEMSET(&ximage, 0, sizeof(XMesaImage));
528         ximage.width = width;
529         ximage.height = height;
530         ximage.format = ZPixmap;
531         ximage.data = (char *) pixels
532            + ((srcY + h - 1) * rowLength + srcX) * 4;
533         ximage.byte_order = LSBFirst;
534         ximage.bitmap_unit = 32;
535         ximage.bitmap_bit_order = LSBFirst;
536         ximage.bitmap_pad = 32;
537         ximage.depth = 32;
538         ximage.bits_per_pixel = 32;
539         ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */
540         /* it seems we don't need to set the ximage.red/green/blue_mask fields */
541         /* flip Y axis for dest position */
542         dstY = YFLIP(xrb, dstY) - h + 1;
543         XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h);
544      }
545
546      if (unpack->BufferObj->Name) {
547         ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
548                                 unpack->BufferObj);
549      }
550   }
551   else {
552      /* software fallback */
553      _swrast_DrawPixels(ctx, x, y, width, height,
554                         format, type, unpack, pixels);
555   }
556}
557
558
559
560/**
561 * Check if we can do an optimized glDrawPixels into an 5R6G5B visual.
562 */
563static GLboolean
564can_do_DrawPixels_5R6G5B(GLcontext *ctx, GLenum format, GLenum type)
565{
566   if (format == GL_RGB &&
567       type == GL_UNSIGNED_SHORT_5_6_5 &&
568       !ctx->Color.DitherFlag &&  /* no dithering */
569       ctx->DrawBuffer &&
570       ctx->DrawBuffer->Name == 0 &&
571       ctx->Pixel.ZoomX == 1.0 &&        /* no zooming */
572       ctx->Pixel.ZoomY == 1.0 &&
573       ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) {
574      const SWcontext *swrast = SWRAST_CONTEXT(ctx);
575
576      if (swrast->NewState)
577         _swrast_validate_derived( ctx );
578
579      if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ {
580         struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
581         if (rb) {
582            struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb->Wrapped);
583            if (xrb &&
584                xrb->pixmap && /* drawing to pixmap or window */
585                xrb->Base.AlphaBits == 0) {
586               return GL_TRUE;
587            }
588         }
589      }
590   }
591   return GL_FALSE;
592}
593
594
595/**
596 * This function implements glDrawPixels() with an XPutImage call when
597 * drawing to the front buffer (X Window drawable).  The image format
598 * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to
599 * match the PF_5R6G5B pixel format.
600 */
601static void
602xmesa_DrawPixels_5R6G5B( GLcontext *ctx,
603                         GLint x, GLint y, GLsizei width, GLsizei height,
604                         GLenum format, GLenum type,
605                         const struct gl_pixelstore_attrib *unpack,
606                         const GLvoid *pixels )
607{
608   if (can_do_DrawPixels_5R6G5B(ctx, format, type)) {
609      const SWcontext *swrast = SWRAST_CONTEXT( ctx );
610      struct gl_pixelstore_attrib clippedUnpack = *unpack;
611      int dstX = x;
612      int dstY = y;
613      int w = width;
614      int h = height;
615
616      if (swrast->NewState)
617         _swrast_validate_derived( ctx );
618
619      if (unpack->BufferObj->Name) {
620         /* unpack from PBO */
621         GLubyte *buf;
622         if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
623                                        format, type, pixels)) {
624            _mesa_error(ctx, GL_INVALID_OPERATION,
625                        "glDrawPixels(invalid PBO access)");
626            return;
627         }
628         buf = (GLubyte *) ctx->Driver.MapBuffer(ctx,
629                                                 GL_PIXEL_UNPACK_BUFFER_EXT,
630                                                 GL_READ_ONLY_ARB,
631                                                 unpack->BufferObj);
632         if (!buf) {
633            /* buffer is already mapped - that's an error */
634            _mesa_error(ctx, GL_INVALID_OPERATION,
635                        "glDrawPixels(PBO is mapped)");
636            return;
637         }
638         pixels = ADD_POINTERS(buf, pixels);
639      }
640
641      if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) {
642         const XMesaContext xmesa = XMESA_CONTEXT(ctx);
643         XMesaDisplay *dpy = xmesa->xm_visual->display;
644         XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
645         const XMesaGC gc = xmbuf->cleargc;  /* effected by glColorMask */
646         struct xmesa_renderbuffer *xrb
647            = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped);
648         const int srcX = clippedUnpack.SkipPixels;
649         const int srcY = clippedUnpack.SkipRows;
650         const int rowLength = clippedUnpack.RowLength;
651         XMesaImage ximage;
652
653         ASSERT(xmesa->xm_visual->undithered_pf == PF_5R6G5B);
654         ASSERT(dpy);
655         ASSERT(gc);
656
657         /* This is a little tricky since all coordinates up to now have
658          * been in the OpenGL bottom-to-top orientation.  X is top-to-bottom
659          * so we have to carefully compute the Y coordinates/addresses here.
660          */
661         MEMSET(&ximage, 0, sizeof(XMesaImage));
662         ximage.width = width;
663         ximage.height = height;
664         ximage.format = ZPixmap;
665         ximage.data = (char *) pixels
666            + ((srcY + h - 1) * rowLength + srcX) * 2;
667         ximage.byte_order = LSBFirst;
668         ximage.bitmap_unit = 16;
669         ximage.bitmap_bit_order = LSBFirst;
670         ximage.bitmap_pad = 16;
671         ximage.depth = 16;
672         ximage.bits_per_pixel = 16;
673         ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */
674         /* it seems we don't need to set the ximage.red/green/blue_mask fields */
675         /* flip Y axis for dest position */
676         dstY = YFLIP(xrb, dstY) - h + 1;
677         XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h);
678      }
679
680      if (unpack->BufferObj->Name) {
681         ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
682                                 unpack->BufferObj);
683      }
684   }
685   else {
686      /* software fallback */
687      _swrast_DrawPixels(ctx, x, y, width, height,
688                         format, type, unpack, pixels);
689   }
690}
691
692
693/**
694 * Determine if we can do an optimized glCopyPixels.
695 */
696static GLboolean
697can_do_CopyPixels(GLcontext *ctx, GLenum type)
698{
699   if (type == GL_COLOR &&
700       ctx->_ImageTransferState == 0 &&  /* no color tables, scale/bias, etc */
701       ctx->Pixel.ZoomX == 1.0 &&        /* no zooming */
702       ctx->Pixel.ZoomY == 1.0 &&
703       ctx->Color.DrawBuffer[0] == GL_FRONT &&  /* copy to front buf */
704       ctx->Pixel.ReadBuffer == GL_FRONT &&    /* copy from front buf */
705       ctx->ReadBuffer->_ColorReadBuffer &&
706       ctx->DrawBuffer->_ColorDrawBuffers[0]) {
707      const SWcontext *swrast = SWRAST_CONTEXT( ctx );
708
709      if (swrast->NewState)
710         _swrast_validate_derived( ctx );
711
712      if ((swrast->_RasterMask & ~CLIP_BIT) == 0x0 &&
713          ctx->ReadBuffer &&
714          ctx->ReadBuffer->_ColorReadBuffer &&
715          ctx->DrawBuffer &&
716          ctx->DrawBuffer->_ColorDrawBuffers[0]) {
717         struct xmesa_renderbuffer *srcXrb
718            = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer->Wrapped);
719         struct xmesa_renderbuffer *dstXrb
720            = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped);
721         if (srcXrb->pixmap && dstXrb->pixmap) {
722            return GL_TRUE;
723         }
724      }
725   }
726   return GL_FALSE;
727}
728
729
730/**
731 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
732 * for the color buffer.  Don't support zooming, pixel transfer, etc.
733 * We do support copying from one window to another, ala glXMakeCurrentRead.
734 */
735static void
736xmesa_CopyPixels( GLcontext *ctx,
737                  GLint srcx, GLint srcy, GLsizei width, GLsizei height,
738                  GLint destx, GLint desty, GLenum type )
739{
740   if (can_do_CopyPixels(ctx, type)) {
741      const XMesaContext xmesa = XMESA_CONTEXT(ctx);
742      XMesaDisplay *dpy = xmesa->xm_visual->display;
743      XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
744      const XMesaGC gc = xmbuf->cleargc;  /* effected by glColorMask */
745      struct xmesa_renderbuffer *srcXrb
746         = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer->Wrapped);
747      struct xmesa_renderbuffer *dstXrb
748         = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]->Wrapped);
749
750      ASSERT(dpy);
751      ASSERT(gc);
752
753      /* Note: we don't do any special clipping work here.  We could,
754       * but X will do it for us.
755       */
756      srcy = YFLIP(srcXrb, srcy) - height + 1;
757      desty = YFLIP(dstXrb, desty) - height + 1;
758      XCopyArea(dpy, srcXrb->pixmap, dstXrb->pixmap, gc,
759                srcx, srcy, width, height, destx, desty);
760   }
761   else {
762      _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type );
763   }
764}
765
766#endif /* XFree86Server */
767
768
769
770/*
771 * Every driver should implement a GetString function in order to
772 * return a meaningful GL_RENDERER string.
773 */
774static const GLubyte *
775get_string( GLcontext *ctx, GLenum name )
776{
777   (void) ctx;
778   switch (name) {
779      case GL_RENDERER:
780#ifdef XFree86Server
781         return (const GLubyte *) "Mesa GLX Indirect";
782#else
783         return (const GLubyte *) "Mesa X11";
784#endif
785      case GL_VENDOR:
786#ifdef XFree86Server
787         return (const GLubyte *) "Mesa project: www.mesa3d.org";
788#else
789         return NULL;
790#endif
791      default:
792         return NULL;
793   }
794}
795
796
797/*
798 * We implement the glEnable function only because we care about
799 * dither enable/disable.
800 */
801static void
802enable( GLcontext *ctx, GLenum pname, GLboolean state )
803{
804   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
805
806   switch (pname) {
807      case GL_DITHER:
808         if (state)
809            xmesa->pixelformat = xmesa->xm_visual->dithered_pf;
810         else
811            xmesa->pixelformat = xmesa->xm_visual->undithered_pf;
812         break;
813      default:
814         ;  /* silence compiler warning */
815   }
816}
817
818
819static void
820clear_color_HPCR_ximage( GLcontext *ctx, const GLfloat color[4] )
821{
822   int i;
823   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
824
825   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]);
826   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]);
827   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]);
828   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]);
829
830   if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
831      /* black is black */
832      MEMSET( xmesa->xm_visual->hpcr_clear_ximage_pattern, 0x0 ,
833              sizeof(xmesa->xm_visual->hpcr_clear_ximage_pattern));
834   }
835   else {
836      /* build clear pattern */
837      for (i=0; i<16; i++) {
838         xmesa->xm_visual->hpcr_clear_ximage_pattern[0][i] =
839            DITHER_HPCR(i, 0,
840                        xmesa->clearcolor[0],
841                        xmesa->clearcolor[1],
842                        xmesa->clearcolor[2]);
843         xmesa->xm_visual->hpcr_clear_ximage_pattern[1][i]    =
844            DITHER_HPCR(i, 1,
845                        xmesa->clearcolor[0],
846                        xmesa->clearcolor[1],
847                        xmesa->clearcolor[2]);
848      }
849   }
850}
851
852
853static void
854clear_color_HPCR_pixmap( GLcontext *ctx, const GLfloat color[4] )
855{
856   int i;
857   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
858
859   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]);
860   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]);
861   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]);
862   CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]);
863
864   if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
865      /* black is black */
866      for (i=0; i<16; i++) {
867         XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 0, 0);
868         XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 1, 0);
869      }
870   }
871   else {
872      for (i=0; i<16; i++) {
873         XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 0,
874                       DITHER_HPCR(i, 0,
875                                   xmesa->clearcolor[0],
876                                   xmesa->clearcolor[1],
877                                   xmesa->clearcolor[2]));
878         XMesaPutPixel(xmesa->xm_visual->hpcr_clear_ximage, i, 1,
879                       DITHER_HPCR(i, 1,
880                                   xmesa->clearcolor[0],
881                                   xmesa->clearcolor[1],
882                                   xmesa->clearcolor[2]));
883      }
884   }
885   /* change tile pixmap content */
886   XMesaPutImage(xmesa->display,
887		 (XMesaDrawable)xmesa->xm_visual->hpcr_clear_pixmap,
888		 XMESA_BUFFER(ctx->DrawBuffer)->cleargc,
889		 xmesa->xm_visual->hpcr_clear_ximage, 0, 0, 0, 0, 16, 2);
890}
891
892
893/**
894 * Called when the driver should update its state, based on the new_state
895 * flags.
896 */
897void
898xmesa_update_state( GLcontext *ctx, GLbitfield new_state )
899{
900   const XMesaContext xmesa = XMESA_CONTEXT(ctx);
901
902   /* Propagate statechange information to swrast and swrast_setup
903    * modules.  The X11 driver has no internal GL-dependent state.
904    */
905   _swrast_InvalidateState( ctx, new_state );
906   _tnl_InvalidateState( ctx, new_state );
907   _vbo_InvalidateState( ctx, new_state );
908   _swsetup_InvalidateState( ctx, new_state );
909
910   if (ctx->DrawBuffer->Name != 0)
911      return;
912
913   /*
914    * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect
915    * renderbuffer span/clear funcs.
916    * Check _NEW_COLOR to detect dither enable/disable.
917    */
918   if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) {
919      XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
920      struct xmesa_renderbuffer *front_xrb, *back_xrb;
921
922      front_xrb = xmbuf->frontxrb;
923      if (front_xrb) {
924         xmesa_set_renderbuffer_funcs(front_xrb, xmesa->pixelformat,
925                                      xmesa->xm_visual->BitsPerPixel);
926         front_xrb->clearFunc = clear_pixmap;
927      }
928
929      back_xrb = xmbuf->backxrb;
930      if (back_xrb) {
931         xmesa_set_renderbuffer_funcs(back_xrb, xmesa->pixelformat,
932                                      xmesa->xm_visual->BitsPerPixel);
933         if (xmbuf->backxrb->pixmap) {
934            back_xrb->clearFunc = clear_pixmap;
935         }
936         else {
937            switch (xmesa->xm_visual->BitsPerPixel) {
938            case 8:
939               if (xmesa->xm_visual->hpcr_clear_flag) {
940                  back_xrb->clearFunc = clear_HPCR_ximage;
941               }
942               else {
943                  back_xrb->clearFunc = clear_8bit_ximage;
944               }
945               break;
946            case 16:
947               back_xrb->clearFunc = clear_16bit_ximage;
948               break;
949            case 24:
950               back_xrb->clearFunc = clear_24bit_ximage;
951               break;
952            case 32:
953               back_xrb->clearFunc = clear_32bit_ximage;
954               break;
955            default:
956               back_xrb->clearFunc = clear_nbit_ximage;
957               break;
958            }
959         }
960      }
961   }
962
963   if (xmesa->xm_visual->hpcr_clear_flag) {
964      /* this depends on whether we're drawing to the front or back buffer */
965      /* XXX FIX THIS! */
966#if 0
967      if (pixmap) {
968         ctx->Driver.ClearColor = clear_color_HPCR_pixmap;
969      }
970      else {
971         ctx->Driver.ClearColor = clear_color_HPCR_ximage;
972      }
973#else
974      (void) clear_color_HPCR_pixmap;
975      (void) clear_color_HPCR_ximage;
976#endif
977   }
978}
979
980
981
982/**
983 * Called via ctx->Driver.TestProxyTeximage().  Normally, we'd just use
984 * the _mesa_test_proxy_teximage() fallback function, but we're going to
985 * special-case the 3D texture case to allow textures up to 512x512x32
986 * texels.
987 */
988static GLboolean
989test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
990                    GLint internalFormat, GLenum format, GLenum type,
991                    GLint width, GLint height, GLint depth, GLint border)
992{
993   if (target == GL_PROXY_TEXTURE_3D) {
994      /* special case for 3D textures */
995      if (width * height * depth > 512 * 512 * 64 ||
996          width  < 2 * border ||
997          (!ctx->Extensions.ARB_texture_non_power_of_two &&
998           _mesa_bitcount(width  - 2 * border) != 1) ||
999          height < 2 * border ||
1000          (!ctx->Extensions.ARB_texture_non_power_of_two &&
1001           _mesa_bitcount(height - 2 * border) != 1) ||
1002          depth  < 2 * border ||
1003          (!ctx->Extensions.ARB_texture_non_power_of_two &&
1004           _mesa_bitcount(depth  - 2 * border) != 1)) {
1005         /* Bad size, or too many texels */
1006         return GL_FALSE;
1007      }
1008      return GL_TRUE;
1009   }
1010   else {
1011      /* use the fallback routine for 1D, 2D, cube and rect targets */
1012      return _mesa_test_proxy_teximage(ctx, target, level, internalFormat,
1013                                       format, type, width, height, depth,
1014                                       border);
1015   }
1016}
1017
1018
1019/**
1020 * In SW, we don't really compress GL_COMPRESSED_RGB[A] textures!
1021 */
1022static const struct gl_texture_format *
1023choose_tex_format( GLcontext *ctx, GLint internalFormat,
1024                   GLenum format, GLenum type )
1025{
1026   switch (internalFormat) {
1027      case GL_COMPRESSED_RGB_ARB:
1028         return &_mesa_texformat_rgb;
1029      case GL_COMPRESSED_RGBA_ARB:
1030         return &_mesa_texformat_rgba;
1031      default:
1032         return _mesa_choose_tex_format(ctx, internalFormat, format, type);
1033   }
1034}
1035
1036
1037/**
1038 * Called by glViewport.
1039 * This is a good time for us to poll the current X window size and adjust
1040 * our renderbuffers to match the current window size.
1041 * Remember, we have no opportunity to respond to conventional
1042 * X Resize/StructureNotify events since the X driver has no event loop.
1043 * Thus, we poll.
1044 * Note that this trick isn't fool-proof.  If the application never calls
1045 * glViewport, our notion of the current window size may be incorrect.
1046 * That problem led to the GLX_MESA_resize_buffers extension.
1047 */
1048static void
1049xmesa_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
1050{
1051   XMesaContext xmctx = XMESA_CONTEXT(ctx);
1052   XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer);
1053   XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer);
1054   xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf);
1055   xmesa_check_and_update_buffer_size(xmctx, xmreadbuf);
1056   (void) x;
1057   (void) y;
1058   (void) w;
1059   (void) h;
1060}
1061
1062
1063#if ENABLE_EXT_timer_query
1064
1065/*
1066 * The GL_EXT_timer_query extension is not enabled for the XServer
1067 * indirect renderer.  Not sure about how/if wrapping of gettimeofday()
1068 * is done, etc.
1069 */
1070
1071struct xmesa_query_object
1072{
1073   struct gl_query_object Base;
1074   struct timeval StartTime;
1075};
1076
1077
1078static struct gl_query_object *
1079xmesa_new_query_object(GLcontext *ctx, GLuint id)
1080{
1081   struct xmesa_query_object *q = CALLOC_STRUCT(xmesa_query_object);
1082   if (q) {
1083      q->Base.Id = id;
1084      q->Base.Ready = GL_TRUE;
1085   }
1086   return &q->Base;
1087}
1088
1089
1090static void
1091xmesa_begin_query(GLcontext *ctx, struct gl_query_object *q)
1092{
1093   if (q->Target == GL_TIME_ELAPSED_EXT) {
1094      struct xmesa_query_object *xq = (struct xmesa_query_object *) q;
1095      (void) gettimeofday(&xq->StartTime, NULL);
1096   }
1097}
1098
1099
1100/**
1101 * Return the difference between the two given times in microseconds.
1102 */
1103#ifdef __VMS
1104#define suseconds_t unsigned int
1105#endif
1106static GLuint64EXT
1107time_diff(const struct timeval *t0, const struct timeval *t1)
1108{
1109   GLuint64EXT seconds0 = t0->tv_sec & 0xff;  /* 0 .. 255 seconds */
1110   GLuint64EXT seconds1 = t1->tv_sec & 0xff;  /* 0 .. 255 seconds */
1111   GLuint64EXT nanosec0 = (seconds0 * 1000000 + t0->tv_usec) * 1000;
1112   GLuint64EXT nanosec1 = (seconds1 * 1000000 + t1->tv_usec) * 1000;
1113   return nanosec1 - nanosec0;
1114}
1115
1116
1117static void
1118xmesa_end_query(GLcontext *ctx, struct gl_query_object *q)
1119{
1120   if (q->Target == GL_TIME_ELAPSED_EXT) {
1121      struct xmesa_query_object *xq = (struct xmesa_query_object *) q;
1122      struct timeval endTime;
1123      (void) gettimeofday(&endTime, NULL);
1124      /* result is in nanoseconds! */
1125      q->Result = time_diff(&xq->StartTime, &endTime);
1126   }
1127   q->Ready = GL_TRUE;
1128}
1129
1130#endif /* ENABLE_timer_query */
1131
1132
1133/**
1134 * Initialize the device driver function table with the functions
1135 * we implement in this driver.
1136 */
1137void
1138xmesa_init_driver_functions( XMesaVisual xmvisual,
1139                             struct dd_function_table *driver )
1140{
1141   driver->GetString = get_string;
1142   driver->UpdateState = xmesa_update_state;
1143   driver->GetBufferSize = NULL; /* OBSOLETE */
1144   driver->Flush = finish_or_flush;
1145   driver->Finish = finish_or_flush;
1146   driver->ClearIndex = clear_index;
1147   driver->ClearColor = clear_color;
1148   driver->IndexMask = index_mask;
1149   driver->ColorMask = color_mask;
1150   driver->Enable = enable;
1151   if (TEST_META_FUNCS)
1152      driver->Clear = _mesa_meta_clear;
1153   else
1154      driver->Clear = clear_buffers;
1155   driver->Viewport = xmesa_viewport;
1156#ifndef XFree86Server
1157   driver->CopyPixels = xmesa_CopyPixels;
1158   if (TEST_META_FUNCS) {
1159      driver->DrawPixels = _mesa_meta_draw_pixels;
1160   }
1161   else if (xmvisual->undithered_pf == PF_8R8G8B &&
1162            xmvisual->dithered_pf == PF_8R8G8B &&
1163            xmvisual->BitsPerPixel == 32) {
1164      driver->DrawPixels = xmesa_DrawPixels_8R8G8B;
1165   }
1166   else if (xmvisual->undithered_pf == PF_5R6G5B) {
1167      driver->DrawPixels = xmesa_DrawPixels_5R6G5B;
1168   }
1169#endif
1170   driver->TestProxyTexImage = test_proxy_teximage;
1171#if ENABLE_EXT_texure_compression_s3tc
1172   driver->ChooseTextureFormat = choose_tex_format;
1173#else
1174   (void) choose_tex_format;
1175#endif
1176
1177#if ENABLE_EXT_timer_query
1178   driver->NewQueryObject = xmesa_new_query_object;
1179   driver->BeginQuery = xmesa_begin_query;
1180   driver->EndQuery = xmesa_end_query;
1181#endif
1182}
1183
1184
1185#define XMESA_NEW_POINT  (_NEW_POINT | \
1186                          _NEW_RENDERMODE | \
1187                          _SWRAST_NEW_RASTERMASK)
1188
1189#define XMESA_NEW_LINE   (_NEW_LINE | \
1190                          _NEW_TEXTURE | \
1191                          _NEW_LIGHT | \
1192                          _NEW_DEPTH | \
1193                          _NEW_RENDERMODE | \
1194                          _SWRAST_NEW_RASTERMASK)
1195
1196#define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \
1197                            _NEW_TEXTURE | \
1198                            _NEW_LIGHT | \
1199                            _NEW_DEPTH | \
1200                            _NEW_RENDERMODE | \
1201                            _SWRAST_NEW_RASTERMASK)
1202
1203
1204/**
1205 * Extend the software rasterizer with our line/point/triangle
1206 * functions.
1207 * Called during context creation only.
1208 */
1209void xmesa_register_swrast_functions( GLcontext *ctx )
1210{
1211   SWcontext *swrast = SWRAST_CONTEXT( ctx );
1212
1213   swrast->choose_point = xmesa_choose_point;
1214   swrast->choose_line = xmesa_choose_line;
1215   swrast->choose_triangle = xmesa_choose_triangle;
1216
1217   /* XXX these lines have no net effect.  Remove??? */
1218   swrast->InvalidatePointMask |= XMESA_NEW_POINT;
1219   swrast->InvalidateLineMask |= XMESA_NEW_LINE;
1220   swrast->InvalidateTriangleMask |= XMESA_NEW_TRIANGLE;
1221}
1222