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