xm_api.c revision 8d7d9c22f6aacf1e3bddf39e4305dcc152a498a1
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.3
4 *
5 * Copyright (C) 1999-2005  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 * This file contains the implementations of all the XMesa* functions.
27 *
28 *
29 * NOTES:
30 *
31 * The window coordinate system origin (0,0) is in the lower-left corner
32 * of the window.  X11's window coordinate origin is in the upper-left
33 * corner of the window.  Therefore, most drawing functions in this
34 * file have to flip Y coordinates.
35 *
36 * Define USE_XSHM in the Makefile with -DUSE_XSHM if you want to compile
37 * in support for the MIT Shared Memory extension.  If enabled, when you
38 * use an Ximage for the back buffer in double buffered mode, the "swap"
39 * operation will be faster.  You must also link with -lXext.
40 *
41 * Byte swapping:  If the Mesa host and the X display use a different
42 * byte order then there's some trickiness to be aware of when using
43 * XImages.  The byte ordering used for the XImage is that of the X
44 * display, not the Mesa host.
45 * The color-to-pixel encoding for True/DirectColor must be done
46 * according to the display's visual red_mask, green_mask, and blue_mask.
47 * If XPutPixel is used to put a pixel into an XImage then XPutPixel will
48 * do byte swapping if needed.  If one wants to directly "poke" the pixel
49 * into the XImage's buffer then the pixel must be byte swapped first.  In
50 * Mesa, when byte swapping is needed we use the PF_TRUECOLOR pixel format
51 * and use XPutPixel everywhere except in the implementation of
52 * glClear(GL_COLOR_BUFFER_BIT).  We want this function to be fast so
53 * instead of using XPutPixel we "poke" our values after byte-swapping
54 * the clear pixel value if needed.
55 *
56 */
57
58#ifdef __CYGWIN__
59#undef WIN32
60#undef __WIN32__
61#endif
62
63#include "glxheader.h"
64#include "GL/xmesa.h"
65#include "xmesaP.h"
66#include "context.h"
67#include "extensions.h"
68#include "framebuffer.h"
69#include "glthread.h"
70#include "imports.h"
71#include "matrix.h"
72#include "mtypes.h"
73#include "macros.h"
74#include "renderbuffer.h"
75#include "texformat.h"
76#include "texobj.h"
77#include "texstore.h"
78#include "swrast/swrast.h"
79#include "swrast_setup/swrast_setup.h"
80#include "array_cache/acache.h"
81#include "tnl/tnl.h"
82#include "tnl/t_context.h"
83#include "tnl/t_pipeline.h"
84#include "drivers/common/driverfuncs.h"
85
86#ifdef XFree86Server
87#include <GL/glxtokens.h>
88#endif
89
90/*
91 * Global X driver lock
92 */
93_glthread_Mutex _xmesa_lock;
94
95
96
97/*
98 * Lookup tables for HPCR pixel format:
99 */
100static short hpcr_rgbTbl[3][256] = {
101{
102 16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,  22,  22,  23,  23,
103 24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,  29,  30,  30,  31,  31,
104 32,  32,  33,  33,  34,  34,  35,  35,  36,  36,  37,  37,  38,  38,  39,  39,
105 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
106 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
107 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
108 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
109 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
110112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
111128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
112144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
113160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
114176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
115192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
116208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
117224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239
118},
119{
120 16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,  22,  22,  23,  23,
121 24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,  29,  30,  30,  31,  31,
122 32,  32,  33,  33,  34,  34,  35,  35,  36,  36,  37,  37,  38,  38,  39,  39,
123 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
124 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
125 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
126 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
127 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
128112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
129128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
130144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
131160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
132176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
133192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
134208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
135224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239
136},
137{
138 32,  32,  33,  33,  34,  34,  35,  35,  36,  36,  37,  37,  38,  38,  39,  39,
139 40,  40,  41,  41,  42,  42,  43,  43,  44,  44,  45,  45,  46,  46,  47,  47,
140 48,  48,  49,  49,  50,  50,  51,  51,  52,  52,  53,  53,  54,  54,  55,  55,
141 56,  56,  57,  57,  58,  58,  59,  59,  60,  60,  61,  61,  62,  62,  63,  63,
142 64,  64,  65,  65,  66,  66,  67,  67,  68,  68,  69,  69,  70,  70,  71,  71,
143 72,  72,  73,  73,  74,  74,  75,  75,  76,  76,  77,  77,  78,  78,  79,  79,
144 80,  80,  81,  81,  82,  82,  83,  83,  84,  84,  85,  85,  86,  86,  87,  87,
145 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
146 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
147112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
148128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
149144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
150160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
151176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
152192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
153208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223
154}
155};
156
157
158
159/**********************************************************************/
160/*****                     X Utility Functions                    *****/
161/**********************************************************************/
162
163
164/*
165 * Return the host's byte order as LSBFirst or MSBFirst ala X.
166 */
167#ifndef XFree86Server
168static int host_byte_order( void )
169{
170   int i = 1;
171   char *cptr = (char *) &i;
172   return (*cptr==1) ? LSBFirst : MSBFirst;
173}
174#endif
175
176
177/*
178 * Error handling.
179 */
180#ifndef XFree86Server
181static volatile int mesaXErrorFlag = 0;
182
183static int mesaHandleXError( XMesaDisplay *dpy, XErrorEvent *event )
184{
185   (void) dpy;
186   (void) event;
187   mesaXErrorFlag = 1;
188   return 0;
189}
190#endif
191
192
193/*
194 * Check if the X Shared Memory extension is available.
195 * Return:  0 = not available
196 *          1 = shared XImage support available
197 *          2 = shared Pixmap support available also
198 */
199#ifndef XFree86Server
200static int check_for_xshm( XMesaDisplay *display )
201{
202#ifdef USE_XSHM
203   int major, minor, ignore;
204   Bool pixmaps;
205
206   if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) {
207      if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) {
208	 return (pixmaps==True) ? 2 : 1;
209      }
210      else {
211	 return 0;
212      }
213   }
214   else {
215      return 0;
216   }
217#else
218   /* Can't compile XSHM support */
219   return 0;
220#endif
221}
222#endif
223
224
225/*
226 * Apply gamma correction to an intensity value in [0..max].  Return the
227 * new intensity value.
228 */
229static GLint gamma_adjust( GLfloat gamma, GLint value, GLint max )
230{
231   if (gamma == 1.0) {
232      return value;
233   }
234   else {
235      double x = (double) value / (double) max;
236      return IROUND_POS((GLfloat) max * _mesa_pow(x, 1.0F/gamma));
237   }
238}
239
240
241
242/*
243 * Return the true number of bits per pixel for XImages.
244 * For example, if we request a 24-bit deep visual we may actually need/get
245 * 32bpp XImages.  This function returns the appropriate bpp.
246 * Input:  dpy - the X display
247 *         visinfo - desribes the visual to be used for XImages
248 * Return:  true number of bits per pixel for XImages
249 */
250#ifdef XFree86Server
251
252static int bits_per_pixel( XMesaVisual xmv )
253{
254   const int depth = xmv->nplanes;
255   int i;
256   for (i = 0; i < screenInfo.numPixmapFormats; i++) {
257      if (screenInfo.formats[i].depth == depth)
258         return screenInfo.formats[i].bitsPerPixel;
259   }
260   return depth;  /* should never get here, but this should be safe */
261}
262
263#else
264
265static int bits_per_pixel( XMesaVisual xmv )
266{
267   XMesaDisplay *dpy = xmv->display;
268   XMesaVisualInfo visinfo = xmv->visinfo;
269   XMesaImage *img;
270   int bitsPerPixel;
271   /* Create a temporary XImage */
272   img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
273		       ZPixmap, 0,           /*format, offset*/
274		       (char*) MALLOC(8),    /*data*/
275		       1, 1,                 /*width, height*/
276		       32,                   /*bitmap_pad*/
277		       0                     /*bytes_per_line*/
278                     );
279   assert(img);
280   /* grab the bits/pixel value */
281   bitsPerPixel = img->bits_per_pixel;
282   /* free the XImage */
283   _mesa_free( img->data );
284   img->data = NULL;
285   XMesaDestroyImage( img );
286   return bitsPerPixel;
287}
288#endif
289
290
291
292/*
293 * Determine if a given X window ID is valid (window exists).
294 * Do this by calling XGetWindowAttributes() for the window and
295 * checking if we catch an X error.
296 * Input:  dpy - the display
297 *         win - the window to check for existance
298 * Return:  GL_TRUE - window exists
299 *          GL_FALSE - window doesn't exist
300 */
301#ifndef XFree86Server
302static GLboolean WindowExistsFlag;
303
304static int window_exists_err_handler( XMesaDisplay* dpy, XErrorEvent* xerr )
305{
306   (void) dpy;
307   if (xerr->error_code == BadWindow) {
308      WindowExistsFlag = GL_FALSE;
309   }
310   return 0;
311}
312
313static GLboolean window_exists( XMesaDisplay *dpy, Window win )
314{
315   XWindowAttributes wa;
316   int (*old_handler)( XMesaDisplay*, XErrorEvent* );
317   WindowExistsFlag = GL_TRUE;
318   old_handler = XSetErrorHandler(window_exists_err_handler);
319   XGetWindowAttributes( dpy, win, &wa ); /* dummy request */
320   XSetErrorHandler(old_handler);
321   return WindowExistsFlag;
322}
323#endif
324
325
326
327/**********************************************************************/
328/*****                Linked list of XMesaBuffers                 *****/
329/**********************************************************************/
330
331static XMesaBuffer XMesaBufferList = NULL;
332
333
334/**
335 * Allocate a new XMesaBuffer, initialize basic fields and add to
336 * the list of all buffers.
337 */
338static XMesaBuffer
339alloc_xmesa_buffer(XMesaVisual vis, BufferType type, XMesaColormap cmap)
340{
341   XMesaBuffer b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer);
342   if (b) {
343      b->display = vis->display;
344      b->xm_visual = vis;
345      b->type = type;
346      b->cmap = cmap;
347
348      _mesa_initialize_framebuffer(&b->mesa_buffer, &vis->mesa_visual);
349
350      /* determine back buffer implementation */
351      if (vis->mesa_visual.doubleBufferMode) {
352         if (vis->ximage_flag) {
353            b->db_state = BACK_XIMAGE;
354         }
355         else {
356            b->db_state = BACK_PIXMAP;
357         }
358      }
359      else {
360         b->db_state = 0;
361      }
362
363      /* Allocate the framebuffer's renderbuffers */
364      assert(!b->mesa_buffer.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
365      assert(!b->mesa_buffer.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
366
367      /* front renderbuffer */
368      b->frontxrb = xmesa_new_renderbuffer(NULL, 0, vis->mesa_visual.rgbMode);
369      _mesa_add_renderbuffer(&b->mesa_buffer, BUFFER_FRONT_LEFT,
370                             &b->frontxrb->Base);
371
372      /* back renderbuffer */
373      if (vis->mesa_visual.doubleBufferMode) {
374         b->backxrb =xmesa_new_renderbuffer(NULL, 0, vis->mesa_visual.rgbMode);
375         _mesa_add_renderbuffer(&b->mesa_buffer, BUFFER_BACK_LEFT,
376                                &b->backxrb->Base);
377      }
378
379      _mesa_add_soft_renderbuffers(&b->mesa_buffer,
380                                   GL_FALSE,  /* color */
381                                   vis->mesa_visual.haveDepthBuffer,
382                                   vis->mesa_visual.haveStencilBuffer,
383                                   vis->mesa_visual.haveAccumBuffer,
384                                   vis->mesa_visual.alphaBits > 0,
385                                   vis->mesa_visual.numAuxBuffers > 0 );
386
387      /* insert into linked list */
388      b->Next = XMesaBufferList;
389      XMesaBufferList = b;
390   }
391   return b;
392}
393
394
395/*
396 * Find an XMesaBuffer by matching X display and colormap but NOT matching
397 * the notThis buffer.
398 */
399static XMesaBuffer find_xmesa_buffer(XMesaDisplay *dpy,
400                                     XMesaColormap cmap,
401                                     XMesaBuffer notThis)
402{
403   XMesaBuffer b;
404   for (b=XMesaBufferList; b; b=b->Next) {
405      if (b->display==dpy && b->cmap==cmap && b!=notThis) {
406         return b;
407      }
408   }
409   return NULL;
410}
411
412
413/*
414 * Free an XMesaBuffer, remove from linked list, perhaps free X colormap
415 * entries.
416 */
417static void free_xmesa_buffer(int client, XMesaBuffer buffer)
418{
419   XMesaBuffer prev = NULL, b;
420   (void) client;
421   for (b=XMesaBufferList; b; b=b->Next) {
422      if (b==buffer) {
423         /* unlink bufer from list */
424         if (prev)
425            prev->Next = buffer->Next;
426         else
427            XMesaBufferList = buffer->Next;
428         /* Check to free X colors */
429         if (buffer->num_alloced>0) {
430            /* If no other buffer uses this X colormap then free the colors. */
431            if (!find_xmesa_buffer(buffer->display, buffer->cmap, buffer)) {
432#ifdef XFree86Server
433               (void)FreeColors(buffer->cmap, client,
434				buffer->num_alloced, buffer->alloced_colors,
435				0);
436#else
437               XFreeColors(buffer->display, buffer->cmap,
438                           buffer->alloced_colors, buffer->num_alloced, 0);
439#endif
440            }
441         }
442
443         _mesa_free_framebuffer_data(&buffer->mesa_buffer);
444         /* delete front/back renderbuffers */
445         buffer->frontxrb->Base.Delete(&(buffer->frontxrb->Base));
446         if (buffer->backxrb)
447            buffer->backxrb->Base.Delete(&(buffer->backxrb->Base));
448         _mesa_free(buffer);
449
450         return;
451      }
452      /* continue search */
453      prev = b;
454   }
455   /* buffer not found in XMesaBufferList */
456   _mesa_problem(NULL,"free_xmesa_buffer() - buffer not found\n");
457}
458
459
460/* Copy X color table stuff from one XMesaBuffer to another. */
461static void copy_colortable_info(XMesaBuffer dst, const XMesaBuffer src)
462{
463   MEMCPY(dst->color_table, src->color_table, sizeof(src->color_table));
464   MEMCPY(dst->pixel_to_r, src->pixel_to_r, sizeof(src->pixel_to_r));
465   MEMCPY(dst->pixel_to_g, src->pixel_to_g, sizeof(src->pixel_to_g));
466   MEMCPY(dst->pixel_to_b, src->pixel_to_b, sizeof(src->pixel_to_b));
467   dst->num_alloced = src->num_alloced;
468   MEMCPY(dst->alloced_colors, src->alloced_colors,
469          sizeof(src->alloced_colors));
470}
471
472
473
474/**********************************************************************/
475/*****                   Misc Private Functions                   *****/
476/**********************************************************************/
477
478
479/*
480 * Return number of bits set in n.
481 */
482static int bitcount( unsigned long n )
483{
484   int bits;
485   for (bits=0; n>0; n=n>>1) {
486      if (n&1) {
487         bits++;
488      }
489   }
490   return bits;
491}
492
493
494
495/**
496 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
497 * Return:  GL_TRUE if success, GL_FALSE if error
498 */
499#ifndef XFree86Server
500static GLboolean
501alloc_shm_back_buffer(XMesaBuffer b, GLuint width, GLuint height)
502{
503#ifdef USE_XSHM
504   /*
505    * We have to do a _lot_ of error checking here to be sure we can
506    * really use the XSHM extension.  It seems different servers trigger
507    * errors at different points if the extension won't work.  Therefore
508    * we have to be very careful...
509    */
510   GC gc;
511   int (*old_handler)( XMesaDisplay *, XErrorEvent * );
512
513   if (width == 0 || height == 0) {
514      /* this will be true the first time we're called on 'b' */
515      return GL_FALSE;
516   }
517
518   b->backxrb->ximage = XShmCreateImage(b->xm_visual->display,
519                                        b->xm_visual->visinfo->visual,
520                                        b->xm_visual->visinfo->depth,
521                                        ZPixmap, NULL, &b->shminfo,
522                                        width, height);
523   if (b->backxrb->ximage == NULL) {
524      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (XShmCreateImage), disabling.");
525      b->shm = 0;
526      return GL_FALSE;
527   }
528
529   b->shminfo.shmid = shmget( IPC_PRIVATE, b->backxrb->ximage->bytes_per_line
530			     * b->backxrb->ximage->height, IPC_CREAT|0777 );
531   if (b->shminfo.shmid < 0) {
532      _mesa_warning(NULL, "shmget failed while allocating back buffer");
533      XDestroyImage( b->backxrb->ximage );
534      b->backxrb->ximage = NULL;
535      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (shmget), disabling.");
536      b->shm = 0;
537      return GL_FALSE;
538   }
539
540   b->shminfo.shmaddr = b->backxrb->ximage->data
541                      = (char*)shmat( b->shminfo.shmid, 0, 0 );
542   if (b->shminfo.shmaddr == (char *) -1) {
543      _mesa_warning(NULL, "shmat() failed while allocating back buffer");
544      XDestroyImage( b->backxrb->ximage );
545      shmctl( b->shminfo.shmid, IPC_RMID, 0 );
546      b->backxrb->ximage = NULL;
547      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (shmat), disabling.");
548      b->shm = 0;
549      return GL_FALSE;
550   }
551
552   b->shminfo.readOnly = False;
553   mesaXErrorFlag = 0;
554   old_handler = XSetErrorHandler( mesaHandleXError );
555   /* This may trigger the X protocol error we're ready to catch: */
556   XShmAttach( b->xm_visual->display, &b->shminfo );
557   XSync( b->xm_visual->display, False );
558
559   if (mesaXErrorFlag) {
560      /* we are on a remote display, this error is normal, don't print it */
561      XFlush( b->xm_visual->display );
562      mesaXErrorFlag = 0;
563      XDestroyImage( b->backxrb->ximage );
564      shmdt( b->shminfo.shmaddr );
565      shmctl( b->shminfo.shmid, IPC_RMID, 0 );
566      b->backxrb->ximage = NULL;
567      b->shm = 0;
568      (void) XSetErrorHandler( old_handler );
569      return GL_FALSE;
570   }
571
572   shmctl( b->shminfo.shmid, IPC_RMID, 0 ); /* nobody else needs it */
573
574   /* Finally, try an XShmPutImage to be really sure the extension works */
575   gc = XCreateGC( b->xm_visual->display, b->frontxrb->pixmap, 0, NULL );
576   XShmPutImage( b->xm_visual->display, b->frontxrb->pixmap, gc,
577		 b->backxrb->ximage, 0, 0, 0, 0, 1, 1 /*one pixel*/, False );
578   XSync( b->xm_visual->display, False );
579   XFreeGC( b->xm_visual->display, gc );
580   (void) XSetErrorHandler( old_handler );
581   if (mesaXErrorFlag) {
582      XFlush( b->xm_visual->display );
583      mesaXErrorFlag = 0;
584      XDestroyImage( b->backxrb->ximage );
585      shmdt( b->shminfo.shmaddr );
586      shmctl( b->shminfo.shmid, IPC_RMID, 0 );
587      b->backxrb->ximage = NULL;
588      b->shm = 0;
589      return GL_FALSE;
590   }
591
592   return GL_TRUE;
593#else
594   /* Can't compile XSHM support */
595   return GL_FALSE;
596#endif
597}
598#endif
599
600
601
602/*
603 * Setup an off-screen pixmap or Ximage to use as the back buffer.
604 * Input:  b - the X/Mesa buffer
605 */
606void
607xmesa_alloc_back_buffer( XMesaBuffer b, GLuint width, GLuint height )
608{
609   if (width == 0 || height == 0)
610      return;
611
612   if (b->db_state == BACK_XIMAGE) {
613      /* Deallocate the old backxrb->ximage, if any */
614      if (b->backxrb->ximage) {
615#if defined(USE_XSHM) && !defined(XFree86Server)
616	 if (b->shm) {
617	    XShmDetach( b->xm_visual->display, &b->shminfo );
618	    XDestroyImage( b->backxrb->ximage );
619	    shmdt( b->shminfo.shmaddr );
620	 }
621	 else
622#endif
623	   XMesaDestroyImage( b->backxrb->ximage );
624	 b->backxrb->ximage = NULL;
625      }
626
627      /* Allocate new back buffer */
628#ifdef XFree86Server
629      {
630	 /* Allocate a regular XImage for the back buffer. */
631	 b->backxrb->ximage = XMesaCreateImage(b->xm_visual->BitsPerPixel,
632					 width, height, NULL);
633#else
634      if (b->shm == 0 || !alloc_shm_back_buffer(b, width, height)) {
635	 /* Allocate a regular XImage for the back buffer. */
636	 b->backxrb->ximage = XCreateImage( b->xm_visual->display,
637                                      b->xm_visual->visinfo->visual,
638                                      GET_VISUAL_DEPTH(b->xm_visual),
639				      ZPixmap, 0,   /* format, offset */
640				      NULL,
641                                      width, height,
642				      8, 0 );  /* pad, bytes_per_line */
643#endif
644	 if (!b->backxrb->ximage) {
645	    _mesa_warning(NULL, "alloc_back_buffer: XCreateImage failed.");
646	 }
647         b->backxrb->ximage->data = (char *) MALLOC( b->backxrb->ximage->height
648                                             * b->backxrb->ximage->bytes_per_line );
649         if (!b->backxrb->ximage->data) {
650            _mesa_warning(NULL, "alloc_back_buffer: MALLOC failed.");
651            XMesaDestroyImage( b->backxrb->ximage );
652            b->backxrb->ximage = NULL;
653         }
654      }
655      b->backxrb->pixmap = None;
656      b->backxrb->ximage = b->backxrb->ximage;
657   }
658   else if (b->db_state==BACK_PIXMAP) {
659      if (!width)
660         width = 1;
661      if (!height)
662         height = 1;
663
664      /* Free the old back pixmap */
665      if (b->backxrb->pixmap) {
666	 XMesaFreePixmap( b->xm_visual->display, b->backxrb->pixmap );
667      }
668      /* Allocate new back pixmap */
669      b->backxrb->pixmap = XMesaCreatePixmap( b->xm_visual->display, b->frontxrb->pixmap,
670					 width, height,
671					 GET_VISUAL_DEPTH(b->xm_visual) );
672      b->backxrb->ximage = NULL;
673   }
674}
675
676
677
678/*
679 * A replacement for XAllocColor.  This function should never
680 * fail to allocate a color.  When XAllocColor fails, we return
681 * the nearest matching color.  If we have to allocate many colors
682 * this function isn't too efficient; the XQueryColors() could be
683 * done just once.
684 * Written by Michael Pichler, Brian Paul, Mark Kilgard
685 * Input:  dpy - X display
686 *         cmap - X colormap
687 *         cmapSize - size of colormap
688 * In/Out: color - the XColor struct
689 * Output:  exact - 1=exact color match, 0=closest match
690 *          alloced - 1=XAlloc worked, 0=XAlloc failed
691 */
692static void
693noFaultXAllocColor( int client,
694                    XMesaDisplay *dpy,
695                    XMesaColormap cmap,
696                    int cmapSize,
697                    XMesaColor *color,
698                    int *exact, int *alloced )
699{
700#ifdef XFree86Server
701   Pixel *ppixIn;
702   xrgb *ctable;
703#else
704   /* we'll try to cache ctable for better remote display performance */
705   static Display *prevDisplay = NULL;
706   static XMesaColormap prevCmap = 0;
707   static int prevCmapSize = 0;
708   static XMesaColor *ctable = NULL;
709#endif
710   XMesaColor subColor;
711   int i, bestmatch;
712   double mindist;       /* 3*2^16^2 exceeds long int precision. */
713
714   (void) client;
715
716   /* First try just using XAllocColor. */
717#ifdef XFree86Server
718   if (AllocColor(cmap,
719		  &color->red, &color->green, &color->blue,
720		  &color->pixel,
721		  client) == Success) {
722#else
723   if (XAllocColor(dpy, cmap, color)) {
724#endif
725      *exact = 1;
726      *alloced = 1;
727      return;
728   }
729
730   /* Alloc failed, search for closest match */
731
732   /* Retrieve color table entries. */
733   /* XXX alloca candidate. */
734#ifdef XFree86Server
735   ppixIn = (Pixel *) MALLOC(cmapSize * sizeof(Pixel));
736   ctable = (xrgb *) MALLOC(cmapSize * sizeof(xrgb));
737   for (i = 0; i < cmapSize; i++) {
738      ppixIn[i] = i;
739   }
740   QueryColors(cmap, cmapSize, ppixIn, ctable);
741#else
742   if (prevDisplay != dpy || prevCmap != cmap
743       || prevCmapSize != cmapSize || !ctable) {
744      /* free previously cached color table */
745      if (ctable)
746         _mesa_free(ctable);
747      /* Get the color table from X */
748      ctable = (XMesaColor *) MALLOC(cmapSize * sizeof(XMesaColor));
749      assert(ctable);
750      for (i = 0; i < cmapSize; i++) {
751         ctable[i].pixel = i;
752      }
753      XQueryColors(dpy, cmap, ctable, cmapSize);
754      prevDisplay = dpy;
755      prevCmap = cmap;
756      prevCmapSize = cmapSize;
757   }
758#endif
759
760   /* Find best match. */
761   bestmatch = -1;
762   mindist = 0.0;
763   for (i = 0; i < cmapSize; i++) {
764      double dr = 0.30 * ((double) color->red - (double) ctable[i].red);
765      double dg = 0.59 * ((double) color->green - (double) ctable[i].green);
766      double db = 0.11 * ((double) color->blue - (double) ctable[i].blue);
767      double dist = dr * dr + dg * dg + db * db;
768      if (bestmatch < 0 || dist < mindist) {
769         bestmatch = i;
770         mindist = dist;
771      }
772   }
773
774   /* Return result. */
775   subColor.red   = ctable[bestmatch].red;
776   subColor.green = ctable[bestmatch].green;
777   subColor.blue  = ctable[bestmatch].blue;
778   /* Try to allocate the closest match color.  This should only
779    * fail if the cell is read/write.  Otherwise, we're incrementing
780    * the cell's reference count.
781    */
782#ifdef XFree86Server
783   if (AllocColor(cmap,
784		  &subColor.red, &subColor.green, &subColor.blue,
785		  &subColor.pixel,
786		  client) == Success) {
787#else
788   if (XAllocColor(dpy, cmap, &subColor)) {
789#endif
790      *alloced = 1;
791   }
792   else {
793      /* do this to work around a problem reported by Frank Ortega */
794      subColor.pixel = (unsigned long) bestmatch;
795      subColor.red   = ctable[bestmatch].red;
796      subColor.green = ctable[bestmatch].green;
797      subColor.blue  = ctable[bestmatch].blue;
798      subColor.flags = DoRed | DoGreen | DoBlue;
799      *alloced = 0;
800   }
801#ifdef XFree86Server
802   _mesa_free(ppixIn);
803   _mesa_free(ctable);
804#else
805   /* don't free table, save it for next time */
806#endif
807
808   *color = subColor;
809   *exact = 0;
810}
811
812
813
814
815/*
816 * Do setup for PF_GRAYSCALE pixel format.
817 * Note that buffer may be NULL.
818 */
819static GLboolean setup_grayscale( int client, XMesaVisual v,
820                                  XMesaBuffer buffer, XMesaColormap cmap )
821{
822   if (GET_VISUAL_DEPTH(v)<4 || GET_VISUAL_DEPTH(v)>16) {
823      return GL_FALSE;
824   }
825
826   if (buffer) {
827      XMesaBuffer prevBuffer;
828
829      if (!cmap) {
830         return GL_FALSE;
831      }
832
833      prevBuffer = find_xmesa_buffer(v->display, cmap, buffer);
834      if (prevBuffer &&
835          (buffer->xm_visual->mesa_visual.rgbMode ==
836           prevBuffer->xm_visual->mesa_visual.rgbMode)) {
837         /* Copy colormap stuff from previous XMesaBuffer which uses same
838          * X colormap.  Do this to avoid time spent in noFaultXAllocColor.
839          */
840         copy_colortable_info(buffer, prevBuffer);
841      }
842      else {
843         /* Allocate 256 shades of gray */
844         int gray;
845         int colorsfailed = 0;
846         for (gray=0;gray<256;gray++) {
847            GLint r = gamma_adjust( v->RedGamma,   gray, 255 );
848            GLint g = gamma_adjust( v->GreenGamma, gray, 255 );
849            GLint b = gamma_adjust( v->BlueGamma,  gray, 255 );
850            int exact, alloced;
851            XMesaColor xcol;
852            xcol.red   = (r << 8) | r;
853            xcol.green = (g << 8) | g;
854            xcol.blue  = (b << 8) | b;
855            noFaultXAllocColor( client, v->display,
856                                cmap, GET_COLORMAP_SIZE(v),
857                                &xcol, &exact, &alloced );
858            if (!exact) {
859               colorsfailed++;
860            }
861            if (alloced) {
862               assert(buffer->num_alloced<256);
863               buffer->alloced_colors[buffer->num_alloced] = xcol.pixel;
864               buffer->num_alloced++;
865            }
866
867            /*OLD
868            assert(gray < 576);
869            buffer->color_table[gray*3+0] = xcol.pixel;
870            buffer->color_table[gray*3+1] = xcol.pixel;
871            buffer->color_table[gray*3+2] = xcol.pixel;
872            assert(xcol.pixel < 65536);
873            buffer->pixel_to_r[xcol.pixel] = gray * 30 / 100;
874            buffer->pixel_to_g[xcol.pixel] = gray * 59 / 100;
875            buffer->pixel_to_b[xcol.pixel] = gray * 11 / 100;
876            */
877            buffer->color_table[gray] = xcol.pixel;
878            assert(xcol.pixel < 65536);
879            buffer->pixel_to_r[xcol.pixel] = gray;
880            buffer->pixel_to_g[xcol.pixel] = gray;
881            buffer->pixel_to_b[xcol.pixel] = gray;
882         }
883
884         if (colorsfailed && _mesa_getenv("MESA_DEBUG")) {
885            _mesa_warning(NULL,
886                  "Note: %d out of 256 needed colors do not match exactly.\n",
887                  colorsfailed );
888         }
889      }
890   }
891
892   v->dithered_pf = PF_Grayscale;
893   v->undithered_pf = PF_Grayscale;
894   return GL_TRUE;
895}
896
897
898
899/*
900 * Setup RGB rendering for a window with a PseudoColor, StaticColor,
901 * or 8-bit TrueColor visual visual.  We try to allocate a palette of 225
902 * colors (5 red, 9 green, 5 blue) and dither to approximate a 24-bit RGB
903 * color.  While this function was originally designed just for 8-bit
904 * visuals, it has also proven to work from 4-bit up to 16-bit visuals.
905 * Dithering code contributed by Bob Mercier.
906 */
907static GLboolean setup_dithered_color( int client, XMesaVisual v,
908                                       XMesaBuffer buffer, XMesaColormap cmap )
909{
910   if (GET_VISUAL_DEPTH(v)<4 || GET_VISUAL_DEPTH(v)>16) {
911      return GL_FALSE;
912   }
913
914   if (buffer) {
915      XMesaBuffer prevBuffer;
916
917      if (!cmap) {
918         return GL_FALSE;
919      }
920
921      prevBuffer = find_xmesa_buffer(v->display, cmap, buffer);
922      if (prevBuffer &&
923          (buffer->xm_visual->mesa_visual.rgbMode ==
924           prevBuffer->xm_visual->mesa_visual.rgbMode)) {
925         /* Copy colormap stuff from previous, matching XMesaBuffer.
926          * Do this to avoid time spent in noFaultXAllocColor.
927          */
928         copy_colortable_info(buffer, prevBuffer);
929      }
930      else {
931         /* Allocate X colors and initialize color_table[], red_table[], etc */
932         int r, g, b, i;
933         int colorsfailed = 0;
934         for (r = 0; r < DITH_R; r++) {
935            for (g = 0; g < DITH_G; g++) {
936               for (b = 0; b < DITH_B; b++) {
937                  XMesaColor xcol;
938                  int exact, alloced;
939                  xcol.red  =gamma_adjust(v->RedGamma,   r*65535/(DITH_R-1),65535);
940                  xcol.green=gamma_adjust(v->GreenGamma, g*65535/(DITH_G-1),65535);
941                  xcol.blue =gamma_adjust(v->BlueGamma,  b*65535/(DITH_B-1),65535);
942                  noFaultXAllocColor( client, v->display,
943                                      cmap, GET_COLORMAP_SIZE(v),
944                                      &xcol, &exact, &alloced );
945                  if (!exact) {
946                     colorsfailed++;
947                  }
948                  if (alloced) {
949                     assert(buffer->num_alloced<256);
950                     buffer->alloced_colors[buffer->num_alloced] = xcol.pixel;
951                     buffer->num_alloced++;
952                  }
953                  i = DITH_MIX( r, g, b );
954                  assert(i < 576);
955                  buffer->color_table[i] = xcol.pixel;
956                  assert(xcol.pixel < 65536);
957                  buffer->pixel_to_r[xcol.pixel] = r * 255 / (DITH_R-1);
958                  buffer->pixel_to_g[xcol.pixel] = g * 255 / (DITH_G-1);
959                  buffer->pixel_to_b[xcol.pixel] = b * 255 / (DITH_B-1);
960               }
961            }
962         }
963
964         if (colorsfailed && _mesa_getenv("MESA_DEBUG")) {
965            _mesa_warning(NULL,
966                  "Note: %d out of %d needed colors do not match exactly.\n",
967                  colorsfailed, DITH_R * DITH_G * DITH_B );
968         }
969      }
970   }
971
972   v->dithered_pf = PF_Dither;
973   v->undithered_pf = PF_Lookup;
974   return GL_TRUE;
975}
976
977
978/*
979 * Setup for Hewlett Packard Color Recovery 8-bit TrueColor mode.
980 * HPCR simulates 24-bit color fidelity with an 8-bit frame buffer.
981 * Special dithering tables have to be initialized.
982 */
983static void setup_8bit_hpcr( XMesaVisual v )
984{
985   /* HP Color Recovery contributed by:  Alex De Bruyn (ad@lms.be)
986    * To work properly, the atom _HP_RGB_SMOOTH_MAP_LIST must be defined
987    * on the root window AND the colormap obtainable by XGetRGBColormaps
988    * for that atom must be set on the window.  (see also tkInitWindow)
989    * If that colormap is not set, the output will look stripy.
990    */
991
992   /* Setup color tables with gamma correction */
993   int i;
994   double g;
995
996   g = 1.0 / v->RedGamma;
997   for (i=0; i<256; i++) {
998      GLint red = IROUND_POS(255.0 * _mesa_pow( hpcr_rgbTbl[0][i]/255.0, g ));
999      v->hpcr_rgbTbl[0][i] = CLAMP( red, 16, 239 );
1000   }
1001
1002   g = 1.0 / v->GreenGamma;
1003   for (i=0; i<256; i++) {
1004      GLint green = IROUND_POS(255.0 * _mesa_pow( hpcr_rgbTbl[1][i]/255.0, g ));
1005      v->hpcr_rgbTbl[1][i] = CLAMP( green, 16, 239 );
1006   }
1007
1008   g = 1.0 / v->BlueGamma;
1009   for (i=0; i<256; i++) {
1010      GLint blue = IROUND_POS(255.0 * _mesa_pow( hpcr_rgbTbl[2][i]/255.0, g ));
1011      v->hpcr_rgbTbl[2][i] = CLAMP( blue, 32, 223 );
1012   }
1013   v->undithered_pf = PF_HPCR;  /* can't really disable dithering for now */
1014   v->dithered_pf = PF_HPCR;
1015
1016   /* which method should I use to clear */
1017   /* GL_FALSE: keep the ordinary method  */
1018   /* GL_TRUE : clear with dither pattern */
1019   v->hpcr_clear_flag = _mesa_getenv("MESA_HPCR_CLEAR") ? GL_TRUE : GL_FALSE;
1020
1021   if (v->hpcr_clear_flag) {
1022      v->hpcr_clear_pixmap = XMesaCreatePixmap(v->display,
1023                                               DefaultRootWindow(v->display),
1024                                               16, 2, 8);
1025#ifndef XFree86Server
1026      v->hpcr_clear_ximage = XGetImage(v->display, v->hpcr_clear_pixmap,
1027                                       0, 0, 16, 2, AllPlanes, ZPixmap);
1028#endif
1029   }
1030}
1031
1032
1033/*
1034 * Setup RGB rendering for a window with a True/DirectColor visual.
1035 */
1036static void setup_truecolor( XMesaVisual v, XMesaBuffer buffer,
1037                             XMesaColormap cmap )
1038{
1039   unsigned long rmask, gmask, bmask;
1040   (void) buffer;
1041   (void) cmap;
1042
1043   /* Compute red multiplier (mask) and bit shift */
1044   v->rshift = 0;
1045   rmask = GET_REDMASK(v);
1046   while ((rmask & 1)==0) {
1047      v->rshift++;
1048      rmask = rmask >> 1;
1049   }
1050
1051   /* Compute green multiplier (mask) and bit shift */
1052   v->gshift = 0;
1053   gmask = GET_GREENMASK(v);
1054   while ((gmask & 1)==0) {
1055      v->gshift++;
1056      gmask = gmask >> 1;
1057   }
1058
1059   /* Compute blue multiplier (mask) and bit shift */
1060   v->bshift = 0;
1061   bmask = GET_BLUEMASK(v);
1062   while ((bmask & 1)==0) {
1063      v->bshift++;
1064      bmask = bmask >> 1;
1065   }
1066
1067   /*
1068    * Compute component-to-pixel lookup tables and dithering kernel
1069    */
1070   {
1071      static GLubyte kernel[16] = {
1072          0*16,  8*16,  2*16, 10*16,
1073         12*16,  4*16, 14*16,  6*16,
1074          3*16, 11*16,  1*16,  9*16,
1075         15*16,  7*16, 13*16,  5*16,
1076      };
1077      GLint rBits = bitcount(rmask);
1078      GLint gBits = bitcount(gmask);
1079      GLint bBits = bitcount(bmask);
1080      GLint maxBits;
1081      GLuint i;
1082
1083      /* convert pixel components in [0,_mask] to RGB values in [0,255] */
1084      for (i=0; i<=rmask; i++)
1085         v->PixelToR[i] = (unsigned char) ((i * 255) / rmask);
1086      for (i=0; i<=gmask; i++)
1087         v->PixelToG[i] = (unsigned char) ((i * 255) / gmask);
1088      for (i=0; i<=bmask; i++)
1089         v->PixelToB[i] = (unsigned char) ((i * 255) / bmask);
1090
1091      /* convert RGB values from [0,255] to pixel components */
1092
1093      for (i=0;i<256;i++) {
1094         GLint r = gamma_adjust(v->RedGamma,   i, 255);
1095         GLint g = gamma_adjust(v->GreenGamma, i, 255);
1096         GLint b = gamma_adjust(v->BlueGamma,  i, 255);
1097         v->RtoPixel[i] = (r >> (8-rBits)) << v->rshift;
1098         v->GtoPixel[i] = (g >> (8-gBits)) << v->gshift;
1099         v->BtoPixel[i] = (b >> (8-bBits)) << v->bshift;
1100      }
1101      /* overflow protection */
1102      for (i=256;i<512;i++) {
1103         v->RtoPixel[i] = v->RtoPixel[255];
1104         v->GtoPixel[i] = v->GtoPixel[255];
1105         v->BtoPixel[i] = v->BtoPixel[255];
1106      }
1107
1108      /* setup dithering kernel */
1109      maxBits = rBits;
1110      if (gBits > maxBits)  maxBits = gBits;
1111      if (bBits > maxBits)  maxBits = bBits;
1112      for (i=0;i<16;i++) {
1113         v->Kernel[i] = kernel[i] >> maxBits;
1114      }
1115
1116      v->undithered_pf = PF_Truecolor;
1117      v->dithered_pf = (GET_VISUAL_DEPTH(v)<24) ? PF_Dither_True : PF_Truecolor;
1118   }
1119
1120   /*
1121    * Now check for TrueColor visuals which we can optimize.
1122    */
1123   if (   GET_REDMASK(v)  ==0x0000ff
1124       && GET_GREENMASK(v)==0x00ff00
1125       && GET_BLUEMASK(v) ==0xff0000
1126       && CHECK_BYTE_ORDER(v)
1127       && v->BitsPerPixel==32
1128       && sizeof(GLuint)==4
1129       && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
1130      /* common 32 bpp config used on SGI, Sun */
1131      v->undithered_pf = v->dithered_pf = PF_8A8B8G8R;
1132   }
1133   else if (GET_REDMASK(v)  ==0xff0000
1134       &&   GET_GREENMASK(v)==0x00ff00
1135       &&   GET_BLUEMASK(v) ==0x0000ff
1136       && CHECK_BYTE_ORDER(v)
1137       && v->BitsPerPixel==32
1138       && sizeof(GLuint)==4
1139       && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
1140      /* common 32 bpp config used on Linux, HP, IBM */
1141      if (GET_VISUAL_DEPTH(v)==32)
1142	  v->undithered_pf = v->dithered_pf = PF_8A8R8G8B;
1143      else
1144	  v->undithered_pf = v->dithered_pf = PF_8R8G8B;
1145   }
1146   else if (GET_REDMASK(v)  ==0xff0000
1147       &&   GET_GREENMASK(v)==0x00ff00
1148       &&   GET_BLUEMASK(v) ==0x0000ff
1149       && CHECK_BYTE_ORDER(v)
1150       && v->BitsPerPixel==24
1151       && sizeof(GLuint)==4
1152       && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
1153      /* common packed 24 bpp config used on Linux */
1154      v->undithered_pf = v->dithered_pf = PF_8R8G8B24;
1155   }
1156   else if (GET_REDMASK(v)  ==0xf800
1157       &&   GET_GREENMASK(v)==0x07e0
1158       &&   GET_BLUEMASK(v) ==0x001f
1159       && CHECK_BYTE_ORDER(v)
1160       && v->BitsPerPixel==16
1161       && sizeof(GLushort)==2
1162       && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
1163      /* 5-6-5 color weight on common PC VGA boards */
1164      v->undithered_pf = PF_5R6G5B;
1165      v->dithered_pf = PF_Dither_5R6G5B;
1166   }
1167   else if (GET_REDMASK(v)  ==0xe0
1168       &&   GET_GREENMASK(v)==0x1c
1169       &&   GET_BLUEMASK(v) ==0x03
1170       && CHECK_FOR_HPCR(v)) {
1171      setup_8bit_hpcr( v );
1172   }
1173}
1174
1175
1176
1177/*
1178 * Setup RGB rendering for a window with a monochrome visual.
1179 */
1180static void setup_monochrome( XMesaVisual v, XMesaBuffer b )
1181{
1182   (void) b;
1183   v->dithered_pf = v->undithered_pf = PF_1Bit;
1184   /* if black=1 then we must flip pixel values */
1185   v->bitFlip = (GET_BLACK_PIXEL(v) != 0);
1186}
1187
1188
1189
1190/*
1191 * When a context is "made current" for the first time, we can finally
1192 * finish initializing the context's visual and buffer information.
1193 * Input:  v - the XMesaVisual to initialize
1194 *         b - the XMesaBuffer to initialize (may be NULL)
1195 *         rgb_flag - TRUE = RGBA mode, FALSE = color index mode
1196 *         window - the window/pixmap we're rendering into
1197 *         cmap - the colormap associated with the window/pixmap
1198 * Return:  GL_TRUE=success, GL_FALSE=failure
1199 */
1200static GLboolean initialize_visual_and_buffer( int client,
1201                                               XMesaVisual v,
1202                                               XMesaBuffer b,
1203                                               GLboolean rgb_flag,
1204                                               XMesaDrawable window,
1205                                               XMesaColormap cmap )
1206{
1207   struct xmesa_renderbuffer *front_xrb, *back_xrb;
1208#ifndef XFree86Server
1209   XGCValues gcvalues;
1210#endif
1211
1212   if (b) {
1213      assert(b->xm_visual == v);
1214   }
1215
1216   if (b) {
1217      front_xrb = b->frontxrb;
1218      back_xrb = b->backxrb;
1219   }
1220   else {
1221      front_xrb = back_xrb = NULL;
1222   }
1223
1224   /* Save true bits/pixel */
1225   v->BitsPerPixel = bits_per_pixel(v);
1226   assert(v->BitsPerPixel > 0);
1227
1228
1229   if (rgb_flag==GL_FALSE) {
1230      /* COLOR-INDEXED WINDOW:
1231       * Even if the visual is TrueColor or DirectColor we treat it as
1232       * being color indexed.  This is weird but might be useful to someone.
1233       */
1234      v->dithered_pf = v->undithered_pf = PF_Index;
1235      v->mesa_visual.indexBits = GET_VISUAL_DEPTH(v);
1236   }
1237   else {
1238      /* RGB WINDOW:
1239       * We support RGB rendering into almost any kind of visual.
1240       */
1241      const int xclass = v->mesa_visual.visualType;
1242      if (xclass==GLX_TRUE_COLOR || xclass==GLX_DIRECT_COLOR) {
1243	 setup_truecolor( v, b, cmap );
1244      }
1245      else if (xclass==GLX_STATIC_GRAY && GET_VISUAL_DEPTH(v)==1) {
1246	 setup_monochrome( v, b );
1247      }
1248      else if (xclass==GLX_GRAY_SCALE || xclass==GLX_STATIC_GRAY) {
1249         if (!setup_grayscale( client, v, b, cmap )) {
1250            return GL_FALSE;
1251         }
1252      }
1253      else if ((xclass==GLX_PSEUDO_COLOR || xclass==GLX_STATIC_COLOR)
1254               && GET_VISUAL_DEPTH(v)>=4 && GET_VISUAL_DEPTH(v)<=16) {
1255	 if (!setup_dithered_color( client, v, b, cmap )) {
1256            return GL_FALSE;
1257         }
1258      }
1259      else {
1260	 _mesa_warning(NULL, "XMesa: RGB mode rendering not supported in given visual.");
1261	 return GL_FALSE;
1262      }
1263      v->mesa_visual.indexBits = 0;
1264
1265      if (_mesa_getenv("MESA_NO_DITHER")) {
1266	 v->dithered_pf = v->undithered_pf;
1267      }
1268   }
1269
1270
1271   /*
1272    * If MESA_INFO env var is set print out some debugging info
1273    * which can help Brian figure out what's going on when a user
1274    * reports bugs.
1275    */
1276   if (_mesa_getenv("MESA_INFO")) {
1277      _mesa_printf("X/Mesa visual = %p\n", (void *) v);
1278      _mesa_printf("X/Mesa dithered pf = %u\n", v->dithered_pf);
1279      _mesa_printf("X/Mesa undithered pf = %u\n", v->undithered_pf);
1280      _mesa_printf("X/Mesa level = %d\n", v->mesa_visual.level);
1281      _mesa_printf("X/Mesa depth = %d\n", GET_VISUAL_DEPTH(v));
1282      _mesa_printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel);
1283   }
1284
1285   if (b && window) {
1286      /* Do window-specific initializations */
1287
1288      b->frontxrb->pixmap = window;
1289
1290      /* Setup for single/double buffering */
1291      if (v->mesa_visual.doubleBufferMode) {
1292         /* Double buffered */
1293#ifndef XFree86Server
1294         b->shm = check_for_xshm( v->display );
1295#endif
1296         xmesa_alloc_back_buffer(b, b->mesa_buffer.Width, b->mesa_buffer.Height);
1297      }
1298
1299      /* X11 graphics contexts */
1300#ifdef XFree86Server
1301      b->gc = CreateScratchGC(v->display, window->depth);
1302#else
1303      b->gc = XCreateGC( v->display, window, 0, NULL );
1304#endif
1305      XMesaSetFunction( v->display, b->gc, GXcopy );
1306
1307      /* cleargc - for glClear() */
1308#ifdef XFree86Server
1309      b->cleargc = CreateScratchGC(v->display, window->depth);
1310#else
1311      b->cleargc = XCreateGC( v->display, window, 0, NULL );
1312#endif
1313      XMesaSetFunction( v->display, b->cleargc, GXcopy );
1314
1315      /*
1316       * Don't generate Graphics Expose/NoExpose events in swapbuffers().
1317       * Patch contributed by Michael Pichler May 15, 1995.
1318       */
1319#ifdef XFree86Server
1320      b->swapgc = CreateScratchGC(v->display, window->depth);
1321      {
1322	  CARD32 v[1];
1323	  v[0] = FALSE;
1324	  dixChangeGC(NullClient, b->swapgc, GCGraphicsExposures, v, NULL);
1325      }
1326#else
1327      gcvalues.graphics_exposures = False;
1328      b->swapgc = XCreateGC( v->display, window,
1329                              GCGraphicsExposures, &gcvalues);
1330#endif
1331      XMesaSetFunction( v->display, b->swapgc, GXcopy );
1332      /*
1333       * Set fill style and tile pixmap once for all for HPCR stuff
1334       * (instead of doing it each time in clear_color_HPCR_pixmap())
1335       * Initialize whole stuff
1336       * Patch contributed by Jacques Leroy March 8, 1998.
1337       */
1338      if (v->hpcr_clear_flag && back_xrb->pixmap) {
1339	int i;
1340	for (i=0; i<16; i++)
1341        {
1342	   XMesaPutPixel(v->hpcr_clear_ximage, i, 0, 0);
1343	   XMesaPutPixel(v->hpcr_clear_ximage, i, 1, 0);
1344        }
1345        XMesaPutImage(b->display, (XMesaDrawable)v->hpcr_clear_pixmap,
1346		      b->cleargc, v->hpcr_clear_ximage, 0, 0, 0, 0, 16, 2);
1347	XMesaSetFillStyle( v->display, b->cleargc, FillTiled);
1348	XMesaSetTile( v->display, b->cleargc, v->hpcr_clear_pixmap );
1349      }
1350
1351      /* Initialize the row buffer XImage for use in write_color_span() */
1352#ifdef XFree86Server
1353      b->rowimage = XMesaCreateImage(GET_VISUAL_DEPTH(v), MAX_WIDTH, 1,
1354				     (char *)MALLOC(MAX_WIDTH*4));
1355#else
1356      b->rowimage = XCreateImage( v->display,
1357                                  v->visinfo->visual,
1358                                  v->visinfo->depth,
1359                                  ZPixmap, 0,           /*format, offset*/
1360                                  (char*) MALLOC(MAX_WIDTH*4),  /*data*/
1361                                  MAX_WIDTH, 1,         /*width, height*/
1362                                  32,                   /*bitmap_pad*/
1363                                  0                     /*bytes_per_line*/ );
1364#endif
1365      if (!b->rowimage)
1366         return GL_FALSE;
1367   }
1368
1369   return GL_TRUE;
1370}
1371
1372
1373
1374/*
1375 * Convert an RGBA color to a pixel value.
1376 */
1377unsigned long
1378xmesa_color_to_pixel(GLcontext *ctx,
1379                     GLubyte r, GLubyte g, GLubyte b, GLubyte a,
1380                     GLuint pixelFormat)
1381{
1382   XMesaContext xmesa = XMESA_CONTEXT(ctx);
1383   switch (pixelFormat) {
1384      case PF_Index:
1385         return 0;
1386      case PF_Truecolor:
1387         {
1388            unsigned long p;
1389            PACK_TRUECOLOR( p, r, g, b );
1390            return p;
1391         }
1392      case PF_8A8B8G8R:
1393         return PACK_8A8B8G8R( r, g, b, a );
1394      case PF_8A8R8G8B:
1395         return PACK_8A8R8G8B( r, g, b, a );
1396      case PF_8R8G8B:
1397         /* fall through */
1398      case PF_8R8G8B24:
1399         return PACK_8R8G8B( r, g, b );
1400      case PF_5R6G5B:
1401         return PACK_5R6G5B( r, g, b );
1402      case PF_Dither:
1403         {
1404            DITHER_SETUP;
1405            return DITHER( 1, 0, r, g, b );
1406         }
1407      case PF_1Bit:
1408         /* 382 = (3*255)/2 */
1409         return ((r+g+b) > 382) ^ xmesa->xm_visual->bitFlip;
1410      case PF_HPCR:
1411         return DITHER_HPCR(1, 1, r, g, b);
1412      case PF_Lookup:
1413         {
1414            LOOKUP_SETUP;
1415            return LOOKUP( r, g, b );
1416         }
1417      case PF_Grayscale:
1418         return GRAY_RGB( r, g, b );
1419      case PF_Dither_True:
1420         /* fall through */
1421      case PF_Dither_5R6G5B:
1422         {
1423            unsigned long p;
1424            PACK_TRUEDITHER(p, 1, 0, r, g, b);
1425            return p;
1426         }
1427      default:
1428         _mesa_problem(ctx, "Bad pixel format in xmesa_color_to_pixel");
1429   }
1430   return 0;
1431}
1432
1433
1434#define NUM_VISUAL_TYPES   6
1435
1436/**
1437 * Convert an X visual type to a GLX visual type.
1438 *
1439 * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
1440 *        to be converted.
1441 * \return If \c visualType is a valid X visual type, a GLX visual type will
1442 *         be returned.  Otherwise \c GLX_NONE will be returned.
1443 *
1444 * \note
1445 * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
1446 * DRI CVS tree.
1447 */
1448static GLint
1449xmesa_convert_from_x_visual_type( int visualType )
1450{
1451    static const int glx_visual_types[ NUM_VISUAL_TYPES ] = {
1452	GLX_STATIC_GRAY,  GLX_GRAY_SCALE,
1453	GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
1454	GLX_TRUE_COLOR,   GLX_DIRECT_COLOR
1455    };
1456
1457    return ( (unsigned) visualType < NUM_VISUAL_TYPES )
1458	? glx_visual_types[ visualType ] : GLX_NONE;
1459}
1460
1461
1462/**********************************************************************/
1463/*****                       Public Functions                     *****/
1464/**********************************************************************/
1465
1466
1467/*
1468 * Create a new X/Mesa visual.
1469 * Input:  display - X11 display
1470 *         visinfo - an XVisualInfo pointer
1471 *         rgb_flag - GL_TRUE = RGB mode,
1472 *                    GL_FALSE = color index mode
1473 *         alpha_flag - alpha buffer requested?
1474 *         db_flag - GL_TRUE = double-buffered,
1475 *                   GL_FALSE = single buffered
1476 *         stereo_flag - stereo visual?
1477 *         ximage_flag - GL_TRUE = use an XImage for back buffer,
1478 *                       GL_FALSE = use an off-screen pixmap for back buffer
1479 *         depth_size - requested bits/depth values, or zero
1480 *         stencil_size - requested bits/stencil values, or zero
1481 *         accum_red_size - requested bits/red accum values, or zero
1482 *         accum_green_size - requested bits/green accum values, or zero
1483 *         accum_blue_size - requested bits/blue accum values, or zero
1484 *         accum_alpha_size - requested bits/alpha accum values, or zero
1485 *         num_samples - number of samples/pixel if multisampling, or zero
1486 *         level - visual level, usually 0
1487 *         visualCaveat - ala the GLX extension, usually GLX_NONE
1488 * Return;  a new XMesaVisual or 0 if error.
1489 */
1490XMesaVisual XMesaCreateVisual( XMesaDisplay *display,
1491                               XMesaVisualInfo visinfo,
1492                               GLboolean rgb_flag,
1493                               GLboolean alpha_flag,
1494                               GLboolean db_flag,
1495                               GLboolean stereo_flag,
1496                               GLboolean ximage_flag,
1497                               GLint depth_size,
1498                               GLint stencil_size,
1499                               GLint accum_red_size,
1500                               GLint accum_green_size,
1501                               GLint accum_blue_size,
1502                               GLint accum_alpha_size,
1503                               GLint num_samples,
1504                               GLint level,
1505                               GLint visualCaveat )
1506{
1507   char *gamma;
1508   XMesaVisual v;
1509   GLint red_bits, green_bits, blue_bits, alpha_bits;
1510
1511   /* For debugging only */
1512   if (_mesa_getenv("MESA_XSYNC")) {
1513      /* This makes debugging X easier.
1514       * In your debugger, set a breakpoint on _XError to stop when an
1515       * X protocol error is generated.
1516       */
1517#ifdef XFree86Server
1518      /* NOT_NEEDED */
1519#else
1520      XSynchronize( display, 1 );
1521#endif
1522   }
1523
1524   v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual);
1525   if (!v) {
1526      return NULL;
1527   }
1528
1529   /*
1530    * In the X server, NULL is passed in for the display.  It will have
1531    * to be set before using this visual.  See XMesaSetVisualDisplay()
1532    * below.
1533    */
1534   v->display = display;
1535
1536   /* Save a copy of the XVisualInfo struct because the user may X_mesa_free()
1537    * the struct but we may need some of the information contained in it
1538    * at a later time.
1539    */
1540#ifndef XFree86Server
1541   v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo));
1542   if(!v->visinfo) {
1543      _mesa_free(v);
1544      return NULL;
1545   }
1546   MEMCPY(v->visinfo, visinfo, sizeof(*visinfo));
1547#endif
1548
1549   /* check for MESA_GAMMA environment variable */
1550   gamma = _mesa_getenv("MESA_GAMMA");
1551   if (gamma) {
1552      v->RedGamma = v->GreenGamma = v->BlueGamma = 0.0;
1553      sscanf( gamma, "%f %f %f", &v->RedGamma, &v->GreenGamma, &v->BlueGamma );
1554      if (v->RedGamma<=0.0)    v->RedGamma = 1.0;
1555      if (v->GreenGamma<=0.0)  v->GreenGamma = v->RedGamma;
1556      if (v->BlueGamma<=0.0)   v->BlueGamma = v->RedGamma;
1557   }
1558   else {
1559      v->RedGamma = v->GreenGamma = v->BlueGamma = 1.0;
1560   }
1561
1562   v->ximage_flag = ximage_flag;
1563
1564#ifdef XFree86Server
1565   /* We could calculate these values by ourselves.  nplanes is either the sum
1566    * of the red, green, and blue bits or the number index bits.
1567    * ColormapEntries is either (1U << index_bits) or
1568    * (1U << max(redBits, greenBits, blueBits)).
1569    */
1570   v->nplanes = visinfo->nplanes;
1571   v->ColormapEntries = visinfo->ColormapEntries;
1572
1573   v->mesa_visual.redMask = visinfo->redMask;
1574   v->mesa_visual.greenMask = visinfo->greenMask;
1575   v->mesa_visual.blueMask = visinfo->blueMask;
1576   v->mesa_visual.visualID = visinfo->vid;
1577   v->mesa_visual.screen = 0; /* FIXME: What should be done here? */
1578#else
1579   v->mesa_visual.redMask = visinfo->red_mask;
1580   v->mesa_visual.greenMask = visinfo->green_mask;
1581   v->mesa_visual.blueMask = visinfo->blue_mask;
1582   v->mesa_visual.visualID = visinfo->visualid;
1583   v->mesa_visual.screen = visinfo->screen;
1584#endif
1585
1586#if defined(XFree86Server) || !(defined(__cplusplus) || defined(c_plusplus))
1587   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class);
1588#else
1589   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
1590#endif
1591
1592   v->mesa_visual.visualRating = visualCaveat;
1593
1594   (void) initialize_visual_and_buffer( 0, v, NULL, rgb_flag, 0, 0 );
1595
1596   {
1597      const int xclass = v->mesa_visual.visualType;
1598      if (xclass==GLX_TRUE_COLOR || xclass==GLX_DIRECT_COLOR) {
1599         red_bits   = bitcount(GET_REDMASK(v));
1600         green_bits = bitcount(GET_GREENMASK(v));
1601         blue_bits  = bitcount(GET_BLUEMASK(v));
1602         alpha_bits = 0;
1603      }
1604      else {
1605         /* this is an approximation */
1606         int depth;
1607         depth = GET_VISUAL_DEPTH(v);
1608         red_bits = depth / 3;
1609         depth -= red_bits;
1610         green_bits = depth / 2;
1611         depth -= green_bits;
1612         blue_bits = depth;
1613         alpha_bits = 0;
1614         assert( red_bits + green_bits + blue_bits == GET_VISUAL_DEPTH(v) );
1615      }
1616   }
1617
1618   if (alpha_flag && alpha_bits == 0)
1619      alpha_bits = 8;
1620
1621   _mesa_initialize_visual( &v->mesa_visual,
1622                            rgb_flag, db_flag, stereo_flag,
1623                            red_bits, green_bits,
1624                            blue_bits, alpha_bits,
1625                            v->mesa_visual.indexBits,
1626                            depth_size,
1627                            stencil_size,
1628                            accum_red_size, accum_green_size,
1629                            accum_blue_size, accum_alpha_size,
1630                            0 );
1631
1632   /* XXX minor hack */
1633   v->mesa_visual.level = level;
1634   return v;
1635}
1636
1637
1638void XMesaSetVisualDisplay( XMesaDisplay *dpy, XMesaVisual v )
1639{
1640    v->display = dpy;
1641}
1642
1643
1644void XMesaDestroyVisual( XMesaVisual v )
1645{
1646#ifndef XFree86Server
1647   _mesa_free(v->visinfo);
1648#endif
1649   _mesa_free(v);
1650}
1651
1652
1653
1654/**
1655 * Create a new XMesaContext.
1656 * \param v  the XMesaVisual
1657 * \param share_list  another XMesaContext with which to share display
1658 *                    lists or NULL if no sharing is wanted.
1659 * \return an XMesaContext or NULL if error.
1660 */
1661XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
1662{
1663   static GLboolean firstTime = GL_TRUE;
1664   XMesaContext c;
1665   GLcontext *mesaCtx;
1666   struct dd_function_table functions;
1667   TNLcontext *tnl;
1668
1669   if (firstTime) {
1670      _glthread_INIT_MUTEX(_xmesa_lock);
1671      firstTime = GL_FALSE;
1672   }
1673
1674   /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */
1675   c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
1676   if (!c)
1677      return NULL;
1678
1679   mesaCtx = &(c->mesa);
1680
1681   /* initialize with default driver functions, then plug in XMesa funcs */
1682   _mesa_init_driver_functions(&functions);
1683   xmesa_init_driver_functions(v, &functions);
1684   if (!_mesa_initialize_context(mesaCtx, &v->mesa_visual,
1685                      share_list ? &(share_list->mesa) : (GLcontext *) NULL,
1686                      &functions, (void *) c)) {
1687      _mesa_free(c);
1688      return NULL;
1689   }
1690
1691   _mesa_enable_sw_extensions(mesaCtx);
1692   _mesa_enable_1_3_extensions(mesaCtx);
1693   _mesa_enable_1_4_extensions(mesaCtx);
1694   _mesa_enable_1_5_extensions(mesaCtx);
1695   _mesa_enable_2_0_extensions(mesaCtx);
1696#if SWTC
1697    if (c->Mesa_DXTn) {
1698       _mesa_enable_extension(c, "GL_EXT_texture_compression_s3tc");
1699       _mesa_enable_extension(c, "GL_S3_s3tc");
1700    }
1701    _mesa_enable_extension(c, "GL_3DFX_texture_compression_FXT1");
1702#endif
1703
1704   /* finish up xmesa context initializations */
1705   c->swapbytes = CHECK_BYTE_ORDER(v) ? GL_FALSE : GL_TRUE;
1706   c->xm_visual = v;
1707   c->xm_buffer = NULL;   /* set later by XMesaMakeCurrent */
1708   c->display = v->display;
1709   c->pixelformat = v->dithered_pf;      /* Dithering is enabled by default */
1710
1711   /* Initialize the software rasterizer and helper modules.
1712    */
1713   if (!_swrast_CreateContext( mesaCtx ) ||
1714       !_ac_CreateContext( mesaCtx ) ||
1715       !_tnl_CreateContext( mesaCtx ) ||
1716       !_swsetup_CreateContext( mesaCtx )) {
1717      _mesa_free_context_data(&c->mesa);
1718      _mesa_free(c);
1719      return NULL;
1720   }
1721
1722   /* tnl setup */
1723   tnl = TNL_CONTEXT(mesaCtx);
1724   tnl->Driver.RunPipeline = _tnl_run_pipeline;
1725   /* swrast setup */
1726   xmesa_register_swrast_functions( mesaCtx );
1727   _swsetup_Wakeup(mesaCtx);
1728
1729   return c;
1730}
1731
1732
1733
1734void XMesaDestroyContext( XMesaContext c )
1735{
1736   GLcontext *mesaCtx = &c->mesa;
1737#ifdef FX
1738   XMesaBuffer xmbuf = XMESA_BUFFER(mesaCtx->DrawBuffer);
1739
1740   if (xmbuf && xmbuf->FXctx)
1741      fxMesaDestroyContext(xmbuf->FXctx);
1742#endif
1743   _swsetup_DestroyContext( mesaCtx );
1744   _swrast_DestroyContext( mesaCtx );
1745   _tnl_DestroyContext( mesaCtx );
1746   _ac_DestroyContext( mesaCtx );
1747   _mesa_free_context_data( mesaCtx );
1748   _mesa_free( c );
1749}
1750
1751
1752
1753/*
1754 * XXX this isn't a public function!  It's a hack for the 3Dfx driver.
1755 * Create a new XMesaBuffer from an X window.
1756 * Input:  v - the XMesaVisual
1757 *         w - the window
1758 *         c - the context
1759 * Return:  new XMesaBuffer or NULL if error
1760 */
1761XMesaBuffer
1762XMesaCreateWindowBuffer2(XMesaVisual v, XMesaWindow w, XMesaContext c)
1763{
1764#ifndef XFree86Server
1765   XWindowAttributes attr;
1766#endif
1767#ifdef FX
1768   char *fxEnvVar;
1769#endif
1770   int client = 0;
1771   XMesaBuffer b;
1772   XMesaColormap cmap;
1773
1774   assert(v);
1775   (void) c;
1776
1777   /* Check that window depth matches visual depth */
1778#ifdef XFree86Server
1779   client = CLIENT_ID(((XMesaDrawable)w)->id);
1780
1781   if (GET_VISUAL_DEPTH(v) != ((XMesaDrawable)w)->depth) {
1782      _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
1783                    GET_VISUAL_DEPTH(v), ((XMesaDrawable) w)->depth);
1784      return NULL;
1785   }
1786#else
1787   XGetWindowAttributes( v->display, w, &attr );
1788
1789   if (GET_VISUAL_DEPTH(v) != attr.depth) {
1790      _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
1791                    GET_VISUAL_DEPTH(v), attr.depth);
1792      return NULL;
1793   }
1794#endif
1795
1796   /* Find colormap */
1797#ifdef XFree86Server
1798   cmap = (ColormapPtr)LookupIDByType(wColormap(w), RT_COLORMAP);
1799#else
1800   if (attr.colormap) {
1801      cmap = attr.colormap;
1802   }
1803   else {
1804      _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w);
1805      /* this is weird, a window w/out a colormap!? */
1806      /* OK, let's just allocate a new one and hope for the best */
1807      cmap = XCreateColormap(v->display, w, attr.visual, AllocNone);
1808   }
1809#endif
1810
1811   b = alloc_xmesa_buffer(v, WINDOW, cmap);
1812   if (!b) {
1813      return NULL;
1814   }
1815
1816   if (!initialize_visual_and_buffer( client, v, b, v->mesa_visual.rgbMode,
1817                                      (XMesaDrawable)w, cmap )) {
1818      free_xmesa_buffer(client, b);
1819      return NULL;
1820   }
1821
1822#ifdef FX
1823   fxEnvVar = _mesa_getenv("MESA_GLX_FX");
1824   if (fxEnvVar) {
1825     if (fxEnvVar[0]!='d') {
1826       int attribs[100];
1827       int numAttribs = 0;
1828       int hw;
1829       if (v->mesa_visual.depthBits > 0) {
1830	 attribs[numAttribs++] = FXMESA_DEPTH_SIZE;
1831	 attribs[numAttribs++] = v->mesa_visual.depthBits;
1832       }
1833       if (v->mesa_visual.doubleBufferMode) {
1834	 attribs[numAttribs++] = FXMESA_DOUBLEBUFFER;
1835       }
1836       if (v->mesa_visual.accumRedBits > 0) {
1837	 attribs[numAttribs++] = FXMESA_ACCUM_SIZE;
1838	 attribs[numAttribs++] = v->mesa_visual.accumRedBits;
1839       }
1840       if (v->mesa_visual.stencilBits > 0) {
1841         attribs[numAttribs++] = FXMESA_STENCIL_SIZE;
1842         attribs[numAttribs++] = v->mesa_visual.stencilBits;
1843       }
1844       if (v->mesa_visual.alphaBits > 0) {
1845         attribs[numAttribs++] = FXMESA_ALPHA_SIZE;
1846         attribs[numAttribs++] = v->mesa_visual.alphaBits;
1847       }
1848       if (1) {
1849         attribs[numAttribs++] = FXMESA_SHARE_CONTEXT;
1850         attribs[numAttribs++] = (int) &(c->mesa);
1851       }
1852       attribs[numAttribs++] = FXMESA_NONE;
1853
1854       /* [dBorca] we should take an envvar for `fxMesaSelectCurrentBoard'!!! */
1855       hw = fxMesaSelectCurrentBoard(0);
1856
1857       /* if these fail, there's a new bug somewhere */
1858       ASSERT(b->mesa_buffer.Width > 0);
1859       ASSERT(b->mesa_buffer.Height > 0);
1860
1861       if ((hw == GR_SSTTYPE_VOODOO) || (hw == GR_SSTTYPE_Voodoo2)) {
1862         b->FXctx = fxMesaCreateBestContext(0, b->mesa_buffer.Width,
1863                                            b->mesa_buffer.Height, attribs);
1864         if ((v->undithered_pf!=PF_Index) && (b->backxrb->ximage)) {
1865	   b->FXisHackUsable = b->FXctx ? GL_TRUE : GL_FALSE;
1866	   if (b->FXctx && (fxEnvVar[0]=='w' || fxEnvVar[0]=='W')) {
1867	     b->FXwindowHack = GL_TRUE;
1868	     FX_grSstControl(GR_CONTROL_DEACTIVATE);
1869	   }
1870           else {
1871	     b->FXwindowHack = GL_FALSE;
1872	   }
1873         }
1874       }
1875       else {
1876         if (fxEnvVar[0]=='w' || fxEnvVar[0]=='W')
1877	   b->FXctx = fxMesaCreateContext(w, GR_RESOLUTION_NONE,
1878					  GR_REFRESH_75Hz, attribs);
1879         else
1880	   b->FXctx = fxMesaCreateBestContext(0, b->mesa_buffer.Width,
1881                                              b->mesa_buffer.Height, attribs);
1882         b->FXisHackUsable = GL_FALSE;
1883         b->FXwindowHack = GL_FALSE;
1884       }
1885       /*
1886       fprintf(stderr,
1887               "voodoo %d, wid %d height %d hack: usable %d active %d\n",
1888               hw, b->mesa_buffer.Width, b->mesa_buffer.Height,
1889	       b->FXisHackUsable, b->FXwindowHack);
1890       */
1891     }
1892   }
1893   else {
1894      _mesa_warning(NULL, "WARNING: This Mesa Library includes the Glide driver but\n");
1895      _mesa_warning(NULL, "         you have not defined the MESA_GLX_FX env. var.\n");
1896      _mesa_warning(NULL, "         (check the README.3DFX file for more information).\n\n");
1897      _mesa_warning(NULL, "         you can disable this message with a 'export MESA_GLX_FX=disable'.\n");
1898   }
1899#endif
1900
1901   return b;
1902}
1903
1904
1905XMesaBuffer
1906XMesaCreateWindowBuffer(XMesaVisual v, XMesaWindow w)
1907{
1908   return XMesaCreateWindowBuffer2( v, w, NULL );
1909}
1910
1911
1912/**
1913 * Create a new XMesaBuffer from an X pixmap.
1914 *
1915 * \param v    the XMesaVisual
1916 * \param p    the pixmap
1917 * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or
1918 *             \c GLX_DIRECT_COLOR visual for the pixmap
1919 * \returns new XMesaBuffer or NULL if error
1920 */
1921XMesaBuffer
1922XMesaCreatePixmapBuffer(XMesaVisual v, XMesaPixmap p, XMesaColormap cmap)
1923{
1924   int client = 0;
1925   XMesaBuffer b;
1926
1927   assert(v);
1928
1929   b = alloc_xmesa_buffer(v, PIXMAP, cmap);
1930   if (!b) {
1931      return NULL;
1932   }
1933
1934#ifdef XFree86Server
1935   client = CLIENT_ID(((XMesaDrawable)p)->id);
1936#endif
1937
1938   if (!initialize_visual_and_buffer(client, v, b, v->mesa_visual.rgbMode,
1939				     (XMesaDrawable)p, cmap)) {
1940      free_xmesa_buffer(client, b);
1941      return NULL;
1942   }
1943
1944   return b;
1945}
1946
1947
1948
1949XMesaBuffer
1950XMesaCreatePBuffer(XMesaVisual v, XMesaColormap cmap,
1951                   unsigned int width, unsigned int height)
1952{
1953#ifdef XFree86Server
1954   return 0;
1955#else
1956   int client = 0;
1957   XMesaWindow root;
1958   XMesaDrawable drawable;  /* X Pixmap Drawable */
1959   XMesaBuffer b;
1960
1961   b = alloc_xmesa_buffer(v, PBUFFER, cmap);
1962   if (!b) {
1963      return NULL;
1964   }
1965
1966   /* allocate pixmap for front buffer */
1967   root = RootWindow( v->display, v->visinfo->screen );
1968   drawable = XCreatePixmap( v->display, root, width, height, v->visinfo->depth );
1969
1970   if (!initialize_visual_and_buffer(client, v, b, v->mesa_visual.rgbMode,
1971				     drawable, cmap)) {
1972      free_xmesa_buffer(client, b);
1973      return NULL;
1974   }
1975
1976   return b;
1977#endif
1978}
1979
1980
1981
1982/*
1983 * Deallocate an XMesaBuffer structure and all related info.
1984 */
1985void XMesaDestroyBuffer( XMesaBuffer b )
1986{
1987   int client = 0;
1988
1989#ifdef XFree86Server
1990   if (b->frontxrb->pixmap)
1991       client = CLIENT_ID(b->frontxrb->pixmap->id);
1992#endif
1993
1994   if (b->gc)  XMesaFreeGC( b->xm_visual->display, b->gc );
1995   if (b->cleargc)  XMesaFreeGC( b->xm_visual->display, b->cleargc );
1996   if (b->swapgc)  XMesaFreeGC( b->xm_visual->display, b->swapgc );
1997
1998   if (b->xm_visual->mesa_visual.doubleBufferMode)
1999   {
2000       if (b->backxrb->ximage) {
2001#if defined(USE_XSHM) && !defined(XFree86Server)
2002	   if (b->shm) {
2003	       XShmDetach( b->xm_visual->display, &b->shminfo );
2004	       XDestroyImage( b->backxrb->ximage );
2005	       shmdt( b->shminfo.shmaddr );
2006	   }
2007	   else
2008#endif
2009	       XMesaDestroyImage( b->backxrb->ximage );
2010       }
2011       if (b->backxrb->pixmap) {
2012	   XMesaFreePixmap( b->xm_visual->display, b->backxrb->pixmap );
2013	   if (b->xm_visual->hpcr_clear_flag) {
2014	       XMesaFreePixmap( b->xm_visual->display,
2015				b->xm_visual->hpcr_clear_pixmap );
2016	       XMesaDestroyImage( b->xm_visual->hpcr_clear_ximage );
2017	   }
2018       }
2019   }
2020   if (b->rowimage) {
2021      _mesa_free( b->rowimage->data );
2022      b->rowimage->data = NULL;
2023      XMesaDestroyImage( b->rowimage );
2024   }
2025
2026   free_xmesa_buffer(client, b);
2027}
2028
2029
2030
2031/*
2032 * Bind buffer b to context c and make c the current rendering context.
2033 */
2034GLboolean XMesaMakeCurrent( XMesaContext c, XMesaBuffer b )
2035{
2036   return XMesaMakeCurrent2( c, b, b );
2037}
2038
2039
2040/*
2041 * Bind buffer b to context c and make c the current rendering context.
2042 */
2043GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
2044                             XMesaBuffer readBuffer )
2045{
2046   if (c) {
2047      if (!drawBuffer || !readBuffer)
2048         return GL_FALSE;  /* must specify buffers! */
2049
2050#ifdef FX
2051      if (drawBuffer->FXctx) {
2052         fxMesaMakeCurrent(drawBuffer->FXctx);
2053
2054         c->xm_buffer = drawBuffer;
2055
2056         return GL_TRUE;
2057      }
2058#endif
2059      if (&(c->mesa) == _mesa_get_current_context()
2060          && c->mesa.DrawBuffer == &drawBuffer->mesa_buffer
2061          && c->mesa.ReadBuffer == &readBuffer->mesa_buffer
2062          && ((XMesaBuffer) c->mesa.DrawBuffer)->wasCurrent) {
2063         /* same context and buffer, do nothing */
2064         return GL_TRUE;
2065      }
2066
2067      c->xm_buffer = drawBuffer;
2068
2069      _mesa_make_current(&(c->mesa),
2070                         &drawBuffer->mesa_buffer,
2071                         &readBuffer->mesa_buffer);
2072
2073      if (c->xm_visual->mesa_visual.rgbMode) {
2074         /*
2075          * Must recompute and set these pixel values because colormap
2076          * can be different for different windows.
2077          */
2078         c->clearpixel = xmesa_color_to_pixel( &c->mesa,
2079                                               c->clearcolor[0],
2080                                               c->clearcolor[1],
2081                                               c->clearcolor[2],
2082                                               c->clearcolor[3],
2083                                               c->xm_visual->undithered_pf);
2084         XMesaSetForeground(c->display, drawBuffer->cleargc, c->clearpixel);
2085      }
2086
2087      /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
2088      drawBuffer->wasCurrent = GL_TRUE;
2089   }
2090   else {
2091      /* Detach */
2092      _mesa_make_current( NULL, NULL, NULL );
2093   }
2094   return GL_TRUE;
2095}
2096
2097
2098/*
2099 * Unbind the context c from its buffer.
2100 */
2101GLboolean XMesaUnbindContext( XMesaContext c )
2102{
2103   /* A no-op for XFree86 integration purposes */
2104   return GL_TRUE;
2105}
2106
2107
2108XMesaContext XMesaGetCurrentContext( void )
2109{
2110   GET_CURRENT_CONTEXT(ctx);
2111   if (ctx) {
2112      XMesaContext xmesa = XMESA_CONTEXT(ctx);
2113      return xmesa;
2114   }
2115   else {
2116      return 0;
2117   }
2118}
2119
2120
2121XMesaBuffer XMesaGetCurrentBuffer( void )
2122{
2123   GET_CURRENT_CONTEXT(ctx);
2124   if (ctx) {
2125      XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
2126      return xmbuf;
2127   }
2128   else {
2129      return 0;
2130   }
2131}
2132
2133
2134/* New in Mesa 3.1 */
2135XMesaBuffer XMesaGetCurrentReadBuffer( void )
2136{
2137   GET_CURRENT_CONTEXT(ctx);
2138   if (ctx) {
2139      return (XMesaBuffer) (ctx->ReadBuffer);
2140   }
2141   else {
2142      return 0;
2143   }
2144}
2145
2146
2147GLboolean XMesaForceCurrent(XMesaContext c)
2148{
2149   if (c) {
2150      if (&(c->mesa) != _mesa_get_current_context()) {
2151	 _mesa_make_current(&c->mesa, c->mesa.DrawBuffer, c->mesa.ReadBuffer);
2152      }
2153   }
2154   else {
2155      _mesa_make_current(NULL, NULL, NULL);
2156   }
2157   return GL_TRUE;
2158}
2159
2160
2161GLboolean XMesaLoseCurrent(XMesaContext c)
2162{
2163   (void) c;
2164   _mesa_make_current(NULL, NULL, NULL);
2165   return GL_TRUE;
2166}
2167
2168
2169/*
2170 * Switch 3Dfx support hack between window and full-screen mode.
2171 */
2172GLboolean XMesaSetFXmode( GLint mode )
2173{
2174#ifdef FX
2175   const char *fx = _mesa_getenv("MESA_GLX_FX");
2176   if (fx && fx[0] != 'd') {
2177      GET_CURRENT_CONTEXT(ctx);
2178      GrHwConfiguration hw;
2179      if (!FX_grSstQueryHardware(&hw)) {
2180         /*fprintf(stderr, "!grSstQueryHardware\n");*/
2181         return GL_FALSE;
2182      }
2183      if (hw.num_sst < 1) {
2184         /*fprintf(stderr, "hw.num_sst < 1\n");*/
2185         return GL_FALSE;
2186      }
2187      if (ctx) {
2188         /* [dBorca] Hack alert:
2189	  * oh, this is sooo wrong: ctx above is
2190	  * really an fxMesaContext, not an XMesaContext
2191	  */
2192         XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
2193         if (mode == XMESA_FX_WINDOW) {
2194	    if (xmbuf->FXisHackUsable) {
2195	       FX_grSstControl(GR_CONTROL_DEACTIVATE);
2196	       xmbuf->FXwindowHack = GL_TRUE;
2197	       return GL_TRUE;
2198	    }
2199	 }
2200	 else if (mode == XMESA_FX_FULLSCREEN) {
2201	    FX_grSstControl(GR_CONTROL_ACTIVATE);
2202	    xmbuf->FXwindowHack = GL_FALSE;
2203	    return GL_TRUE;
2204	 }
2205	 else {
2206	    /* Error: Bad mode value */
2207	 }
2208      }
2209   }
2210   /*fprintf(stderr, "fallthrough\n");*/
2211#else
2212   (void) mode;
2213#endif
2214   return GL_FALSE;
2215}
2216
2217
2218
2219#ifdef FX
2220/*
2221 * Read image from VooDoo frame buffer into X/Mesa's back XImage.
2222 */
2223static void FXgetImage( XMesaBuffer b )
2224{
2225   GET_CURRENT_CONTEXT(ctx);
2226   static unsigned short pixbuf[MAX_WIDTH];
2227   GLuint x, y;
2228   int xpos, ypos;
2229   XMesaWindow root;
2230   unsigned int bw, depth, width, height;
2231   XMesaContext xmesa = XMESA_CONTEXT(ctx);
2232
2233#ifdef XFree86Server
2234   x = b->frontxrb->pixmap->x;
2235   y = b->frontxrb->pixmap->y;
2236   width = b->frontxrb->pixmap->width;
2237   height = b->frontxrb->pixmap->height;
2238   depth = b->frontxrb->pixmap->depth;
2239#else
2240   XGetGeometry( b->xm_visual->display, b->frontxrb->pixmap,
2241                 &root, &xpos, &ypos, &width, &height, &bw, &depth);
2242#endif
2243   if (b->mesa_buffer.Width != width || b->mesa_buffer.Height != height) {
2244      b->mesa_buffer.Width = MIN2((int)width, b->FXctx->width);
2245      b->mesa_buffer.Height = MIN2((int)height, b->FXctx->height);
2246      if (b->mesa_buffer.Width & 1)
2247         b->mesa_buffer.Width--;  /* prevent odd width */
2248      xmesa_alloc_back_buffer(b, b->mesa_buffer.Width, b->mesa_buffer.Height);
2249   }
2250
2251   /* [dBorca] we're always in the right GR_COLORFORMAT... aren't we? */
2252   /* grLfbWriteColorFormat(GR_COLORFORMAT_ARGB); */
2253   if (b->xm_visual->undithered_pf==PF_5R6G5B) {
2254      /* Special case: 16bpp RGB */
2255      grLfbReadRegion( GR_BUFFER_FRONTBUFFER,       /* src buffer */
2256                       0, b->FXctx->height - b->mesa_buffer.Height,  /*pos*/
2257                       b->mesa_buffer.Width, b->mesa_buffer.Height,  /* size */
2258                       b->mesa_buffer.Width * sizeof(GLushort), /* stride */
2259                       b->backxrb->ximage->data);         /* dest buffer */
2260   }
2261   else if (b->xm_visual->dithered_pf==PF_Dither
2262	    && GET_VISUAL_DEPTH(b->xm_visual)==8) {
2263      /* Special case: 8bpp RGB */
2264      for (y=0;y<b->mesa_buffer.Height;y++) {
2265         GLubyte *ptr = (GLubyte*) b->backxrb->ximage->data
2266                        + b->backxrb->ximage->bytes_per_line * y;
2267         XDITHER_SETUP(y);
2268
2269         /* read row from 3Dfx frame buffer */
2270         grLfbReadRegion( GR_BUFFER_FRONTBUFFER,
2271                          0, b->FXctx->height-(b->mesa_buffer.Height-y),
2272                          b->mesa_buffer.Width, 1,
2273                          0,
2274                          pixbuf );
2275
2276         /* write to XImage back buffer */
2277         for (x=0;x<b->mesa_buffer.Width;x++) {
2278            GLubyte r = (pixbuf[x] & 0xf800) >> 8;
2279            GLubyte g = (pixbuf[x] & 0x07e0) >> 3;
2280            GLubyte b = (pixbuf[x] & 0x001f) << 3;
2281            *ptr++ = XDITHER( x, r, g, b);
2282         }
2283      }
2284   }
2285   else {
2286      /* General case: slow! */
2287      for (y=0;y<b->mesa_buffer.Height;y++) {
2288         /* read row from 3Dfx frame buffer */
2289         grLfbReadRegion( GR_BUFFER_FRONTBUFFER,
2290                          0, b->FXctx->height-(b->mesa_buffer.Height-y),
2291                          b->mesa_buffer.Width, 1,
2292                          0,
2293                          pixbuf );
2294
2295         /* write to XImage back buffer */
2296         for (x=0;x<b->mesa_buffer.Width;x++) {
2297            XMesaPutPixel(b->backxrb->ximage,x,y,
2298			  xmesa_color_to_pixel(ctx,
2299					       (pixbuf[x] & 0xf800) >> 8,
2300					       (pixbuf[x] & 0x07e0) >> 3,
2301					       (pixbuf[x] & 0x001f) << 3,
2302					       0xff,
2303                                               b->xm_visual->undithered_pf));
2304         }
2305      }
2306   }
2307   /* grLfbWriteColorFormat(GR_COLORFORMAT_ABGR); */
2308}
2309#endif
2310
2311
2312/*
2313 * Copy the back buffer to the front buffer.  If there's no back buffer
2314 * this is a no-op.
2315 */
2316void XMesaSwapBuffers( XMesaBuffer b )
2317{
2318   GET_CURRENT_CONTEXT(ctx);
2319
2320   /* If we're swapping the buffer associated with the current context
2321    * we have to flush any pending rendering commands first.
2322    */
2323   if (ctx && ctx->DrawBuffer == &(b->mesa_buffer))
2324      _mesa_notifySwapBuffers(ctx);
2325
2326   if (b->db_state) {
2327#ifdef FX
2328      if (b->FXctx) {
2329         fxMesaSwapBuffers();
2330
2331         if (b->FXwindowHack)
2332            FXgetImage(b);
2333         else
2334            return;
2335      }
2336#endif
2337     if (b->backxrb->ximage) {
2338	 /* Copy Ximage from host's memory to server's window */
2339#if defined(USE_XSHM) && !defined(XFree86Server)
2340	 if (b->shm) {
2341            /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
2342	    XShmPutImage( b->xm_visual->display, b->frontxrb->pixmap,
2343			  b->swapgc,
2344			  b->backxrb->ximage, 0, 0,
2345			  0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height,
2346                          False );
2347            /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
2348	 }
2349	 else
2350#endif
2351         {
2352            /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
2353            XMesaPutImage( b->xm_visual->display, b->frontxrb->pixmap,
2354			   b->swapgc,
2355			   b->backxrb->ximage, 0, 0,
2356			   0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height );
2357            /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
2358         }
2359      }
2360      else {
2361	 /* Copy pixmap to window on server */
2362         /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
2363	 XMesaCopyArea( b->xm_visual->display,
2364			b->backxrb->pixmap,   /* source drawable */
2365			b->frontxrb->pixmap,  /* dest. drawable */
2366			b->swapgc,
2367			0, 0, b->mesa_buffer.Width, b->mesa_buffer.Height,
2368			0, 0                 /* dest region */
2369		      );
2370         /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
2371      }
2372   }
2373#if !defined(XFree86Server)
2374   XSync( b->xm_visual->display, False );
2375#endif
2376}
2377
2378
2379
2380/*
2381 * Copy sub-region of back buffer to front buffer
2382 */
2383void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
2384{
2385   GET_CURRENT_CONTEXT(ctx);
2386
2387   /* If we're swapping the buffer associated with the current context
2388    * we have to flush any pending rendering commands first.
2389    */
2390   if (ctx && ctx->DrawBuffer == &(b->mesa_buffer))
2391      _mesa_notifySwapBuffers(ctx);
2392
2393   if (b->db_state) {
2394      int yTop = b->mesa_buffer.Height - y - height;
2395#ifdef FX
2396      if (b->FXctx) {
2397         fxMesaSwapBuffers();
2398         if (b->FXwindowHack)
2399            FXgetImage(b);
2400         else
2401            return;
2402      }
2403#endif
2404      if (b->backxrb->ximage) {
2405         /* Copy Ximage from host's memory to server's window */
2406#if defined(USE_XSHM) && !defined(XFree86Server)
2407         if (b->shm) {
2408            /* XXX assuming width and height aren't too large! */
2409            XShmPutImage( b->xm_visual->display, b->frontxrb->pixmap,
2410                          b->swapgc,
2411                          b->backxrb->ximage, x, yTop,
2412                          x, yTop, width, height, False );
2413            /* wait for finished event??? */
2414         }
2415         else
2416#endif
2417         {
2418            /* XXX assuming width and height aren't too large! */
2419            XMesaPutImage( b->xm_visual->display, b->frontxrb->pixmap,
2420			   b->swapgc,
2421			   b->backxrb->ximage, x, yTop,
2422			   x, yTop, width, height );
2423         }
2424      }
2425      else {
2426         /* Copy pixmap to window on server */
2427         XMesaCopyArea( b->xm_visual->display,
2428			b->backxrb->pixmap,           /* source drawable */
2429			b->frontxrb->pixmap,          /* dest. drawable */
2430			b->swapgc,
2431			x, yTop, width, height,  /* source region */
2432			x, yTop                  /* dest region */
2433                      );
2434      }
2435   }
2436}
2437
2438
2439/*
2440 * Return a pointer to the XMesa backbuffer Pixmap or XImage.  This function
2441 * is a way to get "under the hood" of X/Mesa so one can manipulate the
2442 * back buffer directly.
2443 * Output:  pixmap - pointer to back buffer's Pixmap, or 0
2444 *          ximage - pointer to back buffer's XImage, or NULL
2445 * Return:  GL_TRUE = context is double buffered
2446 *          GL_FALSE = context is single buffered
2447 */
2448GLboolean XMesaGetBackBuffer( XMesaBuffer b,
2449                              XMesaPixmap *pixmap,
2450                              XMesaImage **ximage )
2451{
2452   if (b->db_state) {
2453      if (pixmap)  *pixmap = b->backxrb->pixmap;
2454      if (ximage)  *ximage = b->backxrb->ximage;
2455      return GL_TRUE;
2456   }
2457   else {
2458      *pixmap = 0;
2459      *ximage = NULL;
2460      return GL_FALSE;
2461   }
2462}
2463
2464
2465/*
2466 * Return the depth buffer associated with an XMesaBuffer.
2467 * Input:  b - the XMesa buffer handle
2468 * Output:  width, height - size of buffer in pixels
2469 *          bytesPerValue - bytes per depth value (2 or 4)
2470 *          buffer - pointer to depth buffer values
2471 * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
2472 */
2473GLboolean XMesaGetDepthBuffer( XMesaBuffer b, GLint *width, GLint *height,
2474                               GLint *bytesPerValue, void **buffer )
2475{
2476   struct gl_renderbuffer *rb
2477      = b->mesa_buffer.Attachment[BUFFER_DEPTH].Renderbuffer;
2478   if (!rb || !rb->Data) {
2479      *width = 0;
2480      *height = 0;
2481      *bytesPerValue = 0;
2482      *buffer = 0;
2483      return GL_FALSE;
2484   }
2485   else {
2486      *width = b->mesa_buffer.Width;
2487      *height = b->mesa_buffer.Height;
2488      *bytesPerValue = b->mesa_buffer.Visual.depthBits <= 16
2489         ? sizeof(GLushort) : sizeof(GLuint);
2490      *buffer = rb->Data;
2491      return GL_TRUE;
2492   }
2493}
2494
2495
2496void XMesaFlush( XMesaContext c )
2497{
2498   if (c && c->xm_visual) {
2499#ifdef XFree86Server
2500      /* NOT_NEEDED */
2501#else
2502      XSync( c->xm_visual->display, False );
2503#endif
2504   }
2505}
2506
2507
2508
2509const char *XMesaGetString( XMesaContext c, int name )
2510{
2511   (void) c;
2512   if (name==XMESA_VERSION) {
2513      return "5.0";
2514   }
2515   else if (name==XMESA_EXTENSIONS) {
2516      return "";
2517   }
2518   else {
2519      return NULL;
2520   }
2521}
2522
2523
2524
2525XMesaBuffer XMesaFindBuffer( XMesaDisplay *dpy, XMesaDrawable d )
2526{
2527   XMesaBuffer b;
2528   for (b=XMesaBufferList; b; b=b->Next) {
2529      if (b->frontxrb->pixmap==d && b->display==dpy) {
2530         return b;
2531      }
2532   }
2533   return NULL;
2534}
2535
2536
2537
2538/*
2539 * Look for XMesaBuffers whose X window has been destroyed.
2540 * Deallocate any such XMesaBuffers.
2541 */
2542void XMesaGarbageCollect( void )
2543{
2544   XMesaBuffer b, next;
2545   for (b=XMesaBufferList; b; b=next) {
2546      next = b->Next;
2547      if (b->display && b->frontxrb->pixmap && b->type == WINDOW) {
2548#ifdef XFree86Server
2549	 /* NOT_NEEDED */
2550#else
2551         XSync(b->display, False);
2552         if (!window_exists( b->display, b->frontxrb->pixmap )) {
2553            /* found a dead window, free the ancillary info */
2554            XMesaDestroyBuffer( b );
2555         }
2556#endif
2557      }
2558   }
2559}
2560
2561
2562void XMesaReset( void )
2563{
2564    while (XMesaBufferList)
2565	XMesaDestroyBuffer(XMesaBufferList);
2566
2567    XMesaBufferList = NULL;
2568}
2569
2570
2571unsigned long XMesaDitherColor( XMesaContext xmesa, GLint x, GLint y,
2572                                GLfloat red, GLfloat green,
2573                                GLfloat blue, GLfloat alpha )
2574{
2575   GLcontext *ctx = &xmesa->mesa;
2576   GLint r = (GLint) (red   * 255.0F);
2577   GLint g = (GLint) (green * 255.0F);
2578   GLint b = (GLint) (blue  * 255.0F);
2579   GLint a = (GLint) (alpha * 255.0F);
2580
2581   switch (xmesa->pixelformat) {
2582      case PF_Index:
2583         return 0;
2584      case PF_Truecolor:
2585         {
2586            unsigned long p;
2587            PACK_TRUECOLOR( p, r, g, b );
2588            return p;
2589         }
2590      case PF_8A8B8G8R:
2591         return PACK_8A8B8G8R( r, g, b, a );
2592      case PF_8A8R8G8B:
2593         return PACK_8A8R8G8B( r, g, b, a );
2594      case PF_8R8G8B:
2595         return PACK_8R8G8B( r, g, b );
2596      case PF_5R6G5B:
2597         return PACK_5R6G5B( r, g, b );
2598      case PF_Dither:
2599         {
2600            DITHER_SETUP;
2601            return DITHER( x, y, r, g, b );
2602         }
2603      case PF_1Bit:
2604         /* 382 = (3*255)/2 */
2605         return ((r+g+b) > 382) ^ xmesa->xm_visual->bitFlip;
2606      case PF_HPCR:
2607         return DITHER_HPCR(x, y, r, g, b);
2608      case PF_Lookup:
2609         {
2610            LOOKUP_SETUP;
2611            return LOOKUP( r, g, b );
2612         }
2613      case PF_Grayscale:
2614         return GRAY_RGB( r, g, b );
2615      case PF_Dither_5R6G5B:
2616         /* fall through */
2617      case PF_Dither_True:
2618         {
2619            unsigned long p;
2620            PACK_TRUEDITHER(p, x, y, r, g, b);
2621            return p;
2622         }
2623      default:
2624         _mesa_problem(NULL, "Bad pixel format in XMesaDitherColor");
2625   }
2626   return 0;
2627}
2628
2629
2630/*
2631 * This is typically called when the window size changes and we need
2632 * to reallocate the buffer's back/depth/stencil/accum buffers.
2633 */
2634void XMesaResizeBuffers( XMesaBuffer b )
2635{
2636#ifdef XFree86Server
2637   GET_CURRENT_CONTEXT(ctx);
2638   xmesa_resize_buffers(ctx, &(b->mesa_buffer), 0, 0);
2639#else
2640   Window root;
2641   int xpos, ypos;
2642   unsigned int width, height, bw, depth;
2643   GET_CURRENT_CONTEXT(ctx);
2644   XGetGeometry( b->xm_visual->display, b->frontxrb->pixmap,
2645                 &root, &xpos, &ypos, &width, &height, &bw, &depth);
2646   xmesa_resize_buffers(ctx, &(b->mesa_buffer), width, height);
2647#endif
2648}
2649
2650