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