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