xm_api.c revision 61e843ff4bf9b9e8c4a7a8a485cee852a4f1dd86
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2007  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 * \file xm_api.c
27 *
28 * All the XMesa* API functions.
29 *
30 *
31 * NOTES:
32 *
33 * The window coordinate system origin (0,0) is in the lower-left corner
34 * of the window.  X11's window coordinate origin is in the upper-left
35 * corner of the window.  Therefore, most drawing functions in this
36 * file have to flip Y coordinates.
37 *
38 * Define USE_XSHM in the Makefile with -DUSE_XSHM if you want to compile
39 * in support for the MIT Shared Memory extension.  If enabled, when you
40 * use an Ximage for the back buffer in double buffered mode, the "swap"
41 * operation will be faster.  You must also link with -lXext.
42 *
43 * Byte swapping:  If the Mesa host and the X display use a different
44 * byte order then there's some trickiness to be aware of when using
45 * XImages.  The byte ordering used for the XImage is that of the X
46 * display, not the Mesa host.
47 * The color-to-pixel encoding for True/DirectColor must be done
48 * according to the display's visual red_mask, green_mask, and blue_mask.
49 * If XPutPixel is used to put a pixel into an XImage then XPutPixel will
50 * do byte swapping if needed.  If one wants to directly "poke" the pixel
51 * into the XImage's buffer then the pixel must be byte swapped first.
52 *
53 */
54
55#ifdef __CYGWIN__
56#undef WIN32
57#undef __WIN32__
58#endif
59
60#include "xm_api.h"
61#include "main/context.h"
62#include "main/framebuffer.h"
63
64#include "state_tracker/st_public.h"
65#include "state_tracker/st_context.h"
66#include "pipe/p_defines.h"
67#include "pipe/p_screen.h"
68#include "pipe/p_winsys.h"
69#include "pipe/p_context.h"
70
71#include "xm_winsys.h"
72#include <GL/glx.h>
73
74/**
75 * Global X driver lock
76 */
77pipe_mutex _xmesa_lock;
78
79
80
81/**********************************************************************/
82/*****                     X Utility Functions                    *****/
83/**********************************************************************/
84
85
86/**
87 * Return the host's byte order as LSBFirst or MSBFirst ala X.
88 */
89static int host_byte_order( void )
90{
91   int i = 1;
92   char *cptr = (char *) &i;
93   return (*cptr==1) ? LSBFirst : MSBFirst;
94}
95
96
97/**
98 * Check if the X Shared Memory extension is available.
99 * Return:  0 = not available
100 *          1 = shared XImage support available
101 *          2 = shared Pixmap support available also
102 */
103int xmesa_check_for_xshm( Display *display )
104{
105#if defined(USE_XSHM)
106   int major, minor, ignore;
107   Bool pixmaps;
108
109   if (getenv("SP_NO_RAST"))
110      return 0;
111
112   if (getenv("MESA_NOSHM")) {
113      return 0;
114   }
115
116   if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) {
117      if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) {
118	 return (pixmaps==True) ? 2 : 1;
119      }
120      else {
121	 return 0;
122      }
123   }
124   else {
125      return 0;
126   }
127#else
128   /* No  XSHM support */
129   return 0;
130#endif
131}
132
133
134/**
135 * Return the true number of bits per pixel for XImages.
136 * For example, if we request a 24-bit deep visual we may actually need/get
137 * 32bpp XImages.  This function returns the appropriate bpp.
138 * Input:  dpy - the X display
139 *         visinfo - desribes the visual to be used for XImages
140 * Return:  true number of bits per pixel for XImages
141 */
142static int
143bits_per_pixel( XMesaVisual xmv )
144{
145   Display *dpy = xmv->display;
146   XVisualInfo * visinfo = xmv->visinfo;
147   XImage *img;
148   int bitsPerPixel;
149   /* Create a temporary XImage */
150   img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
151		       ZPixmap, 0,           /*format, offset*/
152		       (char*) MALLOC(8),    /*data*/
153		       1, 1,                 /*width, height*/
154		       32,                   /*bitmap_pad*/
155		       0                     /*bytes_per_line*/
156                     );
157   assert(img);
158   /* grab the bits/pixel value */
159   bitsPerPixel = img->bits_per_pixel;
160   /* free the XImage */
161   _mesa_free( img->data );
162   img->data = NULL;
163   XDestroyImage( img );
164   return bitsPerPixel;
165}
166
167
168
169/*
170 * Determine if a given X window ID is valid (window exists).
171 * Do this by calling XGetWindowAttributes() for the window and
172 * checking if we catch an X error.
173 * Input:  dpy - the display
174 *         win - the window to check for existance
175 * Return:  GL_TRUE - window exists
176 *          GL_FALSE - window doesn't exist
177 */
178static GLboolean WindowExistsFlag;
179
180static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr )
181{
182   (void) dpy;
183   if (xerr->error_code == BadWindow) {
184      WindowExistsFlag = GL_FALSE;
185   }
186   return 0;
187}
188
189static GLboolean window_exists( Display *dpy, Window win )
190{
191   XWindowAttributes wa;
192   int (*old_handler)( Display*, XErrorEvent* );
193   WindowExistsFlag = GL_TRUE;
194   old_handler = XSetErrorHandler(window_exists_err_handler);
195   XGetWindowAttributes( dpy, win, &wa ); /* dummy request */
196   XSetErrorHandler(old_handler);
197   return WindowExistsFlag;
198}
199
200static Status
201get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height )
202{
203   Window root;
204   Status stat;
205   int xpos, ypos;
206   unsigned int w, h, bw, depth;
207   stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
208   *width = w;
209   *height = h;
210   return stat;
211}
212
213
214/**
215 * Return the size of the window (or pixmap) that corresponds to the
216 * given XMesaBuffer.
217 * \param width  returns width in pixels
218 * \param height  returns height in pixels
219 */
220static void
221xmesa_get_window_size(Display *dpy, XMesaBuffer b,
222                      GLuint *width, GLuint *height)
223{
224   Status stat;
225
226   pipe_mutex_lock(_xmesa_lock);
227   XSync(b->xm_visual->display, 0); /* added for Chromium */
228   stat = get_drawable_size(dpy, b->drawable, width, height);
229   pipe_mutex_unlock(_xmesa_lock);
230
231   if (!stat) {
232      /* probably querying a window that's recently been destroyed */
233      _mesa_warning(NULL, "XGetGeometry failed!\n");
234      *width = *height = 1;
235   }
236}
237
238#define GET_REDMASK(__v)        __v->mesa_visual.redMask
239#define GET_GREENMASK(__v)      __v->mesa_visual.greenMask
240#define GET_BLUEMASK(__v)       __v->mesa_visual.blueMask
241
242
243/**
244 * Choose the pixel format for the given visual.
245 * This will tell the gallium driver how to pack pixel data into
246 * drawing surfaces.
247 */
248static GLuint
249choose_pixel_format(XMesaVisual v)
250{
251   boolean native_byte_order = (host_byte_order() ==
252                                ImageByteOrder(v->display));
253
254   if (   GET_REDMASK(v)   == 0x0000ff
255       && GET_GREENMASK(v) == 0x00ff00
256       && GET_BLUEMASK(v)  == 0xff0000
257       && v->BitsPerPixel == 32) {
258      if (native_byte_order) {
259         /* no byteswapping needed */
260         return 0 /* PIXEL_FORMAT_U_A8_B8_G8_R8 */;
261      }
262      else {
263         return PIPE_FORMAT_R8G8B8A8_UNORM;
264      }
265   }
266   else if (   GET_REDMASK(v)   == 0xff0000
267            && GET_GREENMASK(v) == 0x00ff00
268            && GET_BLUEMASK(v)  == 0x0000ff
269            && v->BitsPerPixel == 32) {
270      if (native_byte_order) {
271         /* no byteswapping needed */
272         return PIPE_FORMAT_A8R8G8B8_UNORM;
273      }
274      else {
275         return PIPE_FORMAT_B8G8R8A8_UNORM;
276      }
277   }
278   else if (   GET_REDMASK(v)   == 0xf800
279            && GET_GREENMASK(v) == 0x07e0
280            && GET_BLUEMASK(v)  == 0x001f
281            && native_byte_order
282            && v->BitsPerPixel == 16) {
283      /* 5-6-5 RGB */
284      return PIPE_FORMAT_R5G6B5_UNORM;
285   }
286
287   assert(0);
288   return 0;
289}
290
291
292
293/**********************************************************************/
294/*****                Linked list of XMesaBuffers                 *****/
295/**********************************************************************/
296
297XMesaBuffer XMesaBufferList = NULL;
298
299
300/**
301 * Allocate a new XMesaBuffer object which corresponds to the given drawable.
302 * Note that XMesaBuffer is derived from GLframebuffer.
303 * The new XMesaBuffer will not have any size (Width=Height=0).
304 *
305 * \param d  the corresponding X drawable (window or pixmap)
306 * \param type  either WINDOW, PIXMAP or PBUFFER, describing d
307 * \param vis  the buffer's visual
308 * \param cmap  the window's colormap, if known.
309 * \return new XMesaBuffer or NULL if any problem
310 */
311static XMesaBuffer
312create_xmesa_buffer(Drawable d, BufferType type,
313                    XMesaVisual vis, Colormap cmap)
314{
315   XMesaBuffer b;
316   GLframebuffer *fb;
317   enum pipe_format colorFormat, depthFormat, stencilFormat;
318   uint width, height;
319
320   ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER);
321
322   b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer);
323   if (!b)
324      return NULL;
325
326   b->drawable = d;
327
328   b->xm_visual = vis;
329   b->type = type;
330   b->cmap = cmap;
331
332   /* determine PIPE_FORMATs for buffers */
333   colorFormat = choose_pixel_format(vis);
334
335   if (vis->mesa_visual.depthBits == 0)
336      depthFormat = PIPE_FORMAT_NONE;
337#ifdef GALLIUM_CELL /* XXX temporary for Cell! */
338   else
339      depthFormat = PIPE_FORMAT_S8Z24_UNORM;
340#else
341   else if (vis->mesa_visual.depthBits <= 16)
342      depthFormat = PIPE_FORMAT_Z16_UNORM;
343   else if (vis->mesa_visual.depthBits <= 24)
344      depthFormat = PIPE_FORMAT_S8Z24_UNORM;
345   else
346      depthFormat = PIPE_FORMAT_Z32_UNORM;
347#endif
348
349   if (vis->mesa_visual.stencilBits == 8) {
350      if (depthFormat == PIPE_FORMAT_S8Z24_UNORM)
351         stencilFormat = depthFormat;
352      else
353         stencilFormat = PIPE_FORMAT_S8_UNORM;
354   }
355   else {
356      /* no stencil */
357      stencilFormat = PIPE_FORMAT_NONE;
358      if (depthFormat == PIPE_FORMAT_S8Z24_UNORM) {
359         /* use 24-bit Z, undefined stencil channel */
360         depthFormat = PIPE_FORMAT_X8Z24_UNORM;
361      }
362   }
363
364
365   get_drawable_size(vis->display, d, &width, &height);
366
367   /*
368    * Create framebuffer, but we'll plug in our own renderbuffers below.
369    */
370   b->stfb = st_create_framebuffer(&vis->mesa_visual,
371                                   colorFormat, depthFormat, stencilFormat,
372                                   width, height,
373                                   (void *) b);
374   fb = &b->stfb->Base;
375
376   /*
377    * Create scratch XImage for xmesa_display_surface()
378    */
379   b->tempImage = XCreateImage(vis->display,
380                               vis->visinfo->visual,
381                               vis->visinfo->depth,
382                               ZPixmap, 0,   /* format, offset */
383                               NULL,         /* data */
384                               0, 0,         /* size */
385                               32,           /* bitmap_pad */
386                               0);           /* bytes_per_line */
387
388   /* GLX_EXT_texture_from_pixmap */
389   b->TextureTarget = 0;
390   b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT;
391   b->TextureMipmap = 0;
392
393   /* insert buffer into linked list */
394   b->Next = XMesaBufferList;
395   XMesaBufferList = b;
396
397   return b;
398}
399
400
401/**
402 * Find an XMesaBuffer by matching X display and colormap but NOT matching
403 * the notThis buffer.
404 */
405XMesaBuffer
406xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis)
407{
408   XMesaBuffer b;
409   for (b = XMesaBufferList; b; b = b->Next) {
410      if (b->xm_visual->display == dpy &&
411          b->cmap == cmap &&
412          b != notThis) {
413         return b;
414      }
415   }
416   return NULL;
417}
418
419
420/**
421 * Remove buffer from linked list, delete if no longer referenced.
422 */
423static void
424xmesa_free_buffer(XMesaBuffer buffer)
425{
426   XMesaBuffer prev = NULL, b;
427
428   for (b = XMesaBufferList; b; b = b->Next) {
429      if (b == buffer) {
430         struct gl_framebuffer *fb = &buffer->stfb->Base;
431
432         /* unlink buffer from list */
433         if (prev)
434            prev->Next = buffer->Next;
435         else
436            XMesaBufferList = buffer->Next;
437
438         /* mark as delete pending */
439         fb->DeletePending = GL_TRUE;
440
441         /* Since the X window for the XMesaBuffer is going away, we don't
442          * want to dereference this pointer in the future.
443          */
444         b->drawable = 0;
445
446         buffer->tempImage->data = NULL;
447         XDestroyImage(buffer->tempImage);
448
449         /* Unreference.  If count = zero we'll really delete the buffer */
450         _mesa_unreference_framebuffer(&fb);
451
452         XFreeGC(b->xm_visual->display, b->gc);
453
454         free(buffer);
455
456         return;
457      }
458      /* continue search */
459      prev = b;
460   }
461   /* buffer not found in XMesaBufferList */
462   _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n");
463}
464
465
466
467/**********************************************************************/
468/*****                   Misc Private Functions                   *****/
469/**********************************************************************/
470
471
472/**
473 * When a context is bound for the first time, we can finally finish
474 * initializing the context's visual and buffer information.
475 * \param v  the XMesaVisual to initialize
476 * \param b  the XMesaBuffer to initialize (may be NULL)
477 * \param rgb_flag  TRUE = RGBA mode, FALSE = color index mode
478 * \param window  the window/pixmap we're rendering into
479 * \param cmap  the colormap associated with the window/pixmap
480 * \return GL_TRUE=success, GL_FALSE=failure
481 */
482static GLboolean
483initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
484                             GLboolean rgb_flag, Drawable window,
485                             Colormap cmap)
486{
487   ASSERT(!b || b->xm_visual == v);
488
489   /* Save true bits/pixel */
490   v->BitsPerPixel = bits_per_pixel(v);
491   assert(v->BitsPerPixel > 0);
492
493   if (rgb_flag == GL_FALSE) {
494      /* COLOR-INDEXED WINDOW: not supported*/
495      return GL_FALSE;
496   }
497   else {
498      /* RGB WINDOW:
499       * We support RGB rendering into almost any kind of visual.
500       */
501      const int xclass = v->mesa_visual.visualType;
502      if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) {
503	 _mesa_warning(NULL,
504            "XMesa: RGB mode rendering not supported in given visual.\n");
505	 return GL_FALSE;
506      }
507      v->mesa_visual.indexBits = 0;
508
509      if (v->BitsPerPixel == 32) {
510         /* We use XImages for all front/back buffers.  If an X Window or
511          * X Pixmap is 32bpp, there's no guarantee that the alpha channel
512          * will be preserved.  For XImages we're in luck.
513          */
514         v->mesa_visual.alphaBits = 8;
515      }
516   }
517
518   /*
519    * If MESA_INFO env var is set print out some debugging info
520    * which can help Brian figure out what's going on when a user
521    * reports bugs.
522    */
523   if (_mesa_getenv("MESA_INFO")) {
524      _mesa_printf("X/Mesa visual = %p\n", (void *) v);
525      _mesa_printf("X/Mesa level = %d\n", v->mesa_visual.level);
526      _mesa_printf("X/Mesa depth = %d\n", v->visinfo->depth);
527      _mesa_printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel);
528   }
529
530   if (b && window) {
531      /* these should have been set in create_xmesa_buffer */
532      ASSERT(b->drawable == window);
533
534      /* Setup for single/double buffering */
535      if (v->mesa_visual.doubleBufferMode) {
536         /* Double buffered */
537         b->shm = xmesa_check_for_xshm( v->display );
538      }
539
540      /* X11 graphics context */
541      b->gc = XCreateGC( v->display, window, 0, NULL );
542      XSetFunction( v->display, b->gc, GXcopy );
543   }
544
545   return GL_TRUE;
546}
547
548
549
550#define NUM_VISUAL_TYPES   6
551
552/**
553 * Convert an X visual type to a GLX visual type.
554 *
555 * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
556 *        to be converted.
557 * \return If \c visualType is a valid X visual type, a GLX visual type will
558 *         be returned.  Otherwise \c GLX_NONE will be returned.
559 *
560 * \note
561 * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
562 * DRI CVS tree.
563 */
564static GLint
565xmesa_convert_from_x_visual_type( int visualType )
566{
567    static const int glx_visual_types[ NUM_VISUAL_TYPES ] = {
568	GLX_STATIC_GRAY,  GLX_GRAY_SCALE,
569	GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
570	GLX_TRUE_COLOR,   GLX_DIRECT_COLOR
571    };
572
573    return ( (unsigned) visualType < NUM_VISUAL_TYPES )
574	? glx_visual_types[ visualType ] : GLX_NONE;
575}
576
577
578/**********************************************************************/
579/*****                       Public Functions                     *****/
580/**********************************************************************/
581
582
583/*
584 * Create a new X/Mesa visual.
585 * Input:  display - X11 display
586 *         visinfo - an XVisualInfo pointer
587 *         rgb_flag - GL_TRUE = RGB mode,
588 *                    GL_FALSE = color index mode
589 *         alpha_flag - alpha buffer requested?
590 *         db_flag - GL_TRUE = double-buffered,
591 *                   GL_FALSE = single buffered
592 *         stereo_flag - stereo visual?
593 *         ximage_flag - GL_TRUE = use an XImage for back buffer,
594 *                       GL_FALSE = use an off-screen pixmap for back buffer
595 *         depth_size - requested bits/depth values, or zero
596 *         stencil_size - requested bits/stencil values, or zero
597 *         accum_red_size - requested bits/red accum values, or zero
598 *         accum_green_size - requested bits/green accum values, or zero
599 *         accum_blue_size - requested bits/blue accum values, or zero
600 *         accum_alpha_size - requested bits/alpha accum values, or zero
601 *         num_samples - number of samples/pixel if multisampling, or zero
602 *         level - visual level, usually 0
603 *         visualCaveat - ala the GLX extension, usually GLX_NONE
604 * Return;  a new XMesaVisual or 0 if error.
605 */
606PUBLIC
607XMesaVisual XMesaCreateVisual( Display *display,
608                               XVisualInfo * visinfo,
609                               GLboolean rgb_flag,
610                               GLboolean alpha_flag,
611                               GLboolean db_flag,
612                               GLboolean stereo_flag,
613                               GLboolean ximage_flag,
614                               GLint depth_size,
615                               GLint stencil_size,
616                               GLint accum_red_size,
617                               GLint accum_green_size,
618                               GLint accum_blue_size,
619                               GLint accum_alpha_size,
620                               GLint num_samples,
621                               GLint level,
622                               GLint visualCaveat )
623{
624   XMesaVisual v;
625   GLint red_bits, green_bits, blue_bits, alpha_bits;
626
627   /* For debugging only */
628   if (_mesa_getenv("MESA_XSYNC")) {
629      /* This makes debugging X easier.
630       * In your debugger, set a breakpoint on _XError to stop when an
631       * X protocol error is generated.
632       */
633      XSynchronize( display, 1 );
634   }
635
636   v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual);
637   if (!v) {
638      return NULL;
639   }
640
641   v->display = display;
642
643   /* Save a copy of the XVisualInfo struct because the user may X_mesa_free()
644    * the struct but we may need some of the information contained in it
645    * at a later time.
646    */
647   v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo));
648   if(!v->visinfo) {
649      _mesa_free(v);
650      return NULL;
651   }
652   MEMCPY(v->visinfo, visinfo, sizeof(*visinfo));
653
654   v->ximage_flag = ximage_flag;
655
656   v->mesa_visual.redMask = visinfo->red_mask;
657   v->mesa_visual.greenMask = visinfo->green_mask;
658   v->mesa_visual.blueMask = visinfo->blue_mask;
659   v->mesa_visual.visualID = visinfo->visualid;
660   v->mesa_visual.screen = visinfo->screen;
661
662#if !(defined(__cplusplus) || defined(c_plusplus))
663   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class);
664#else
665   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
666#endif
667
668   v->mesa_visual.visualRating = visualCaveat;
669
670   if (alpha_flag)
671      v->mesa_visual.alphaBits = 8;
672
673   (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 );
674
675   {
676      const int xclass = v->mesa_visual.visualType;
677      if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
678         red_bits   = _mesa_bitcount(GET_REDMASK(v));
679         green_bits = _mesa_bitcount(GET_GREENMASK(v));
680         blue_bits  = _mesa_bitcount(GET_BLUEMASK(v));
681      }
682      else {
683         /* this is an approximation */
684         int depth;
685         depth = v->visinfo->depth;
686         red_bits = depth / 3;
687         depth -= red_bits;
688         green_bits = depth / 2;
689         depth -= green_bits;
690         blue_bits = depth;
691         alpha_bits = 0;
692         assert( red_bits + green_bits + blue_bits == v->visinfo->depth );
693      }
694      alpha_bits = v->mesa_visual.alphaBits;
695   }
696
697   _mesa_initialize_visual( &v->mesa_visual,
698                            rgb_flag, db_flag, stereo_flag,
699                            red_bits, green_bits,
700                            blue_bits, alpha_bits,
701                            v->mesa_visual.indexBits,
702                            depth_size,
703                            stencil_size,
704                            accum_red_size, accum_green_size,
705                            accum_blue_size, accum_alpha_size,
706                            0 );
707
708   /* XXX minor hack */
709   v->mesa_visual.level = level;
710   return v;
711}
712
713
714PUBLIC
715void XMesaDestroyVisual( XMesaVisual v )
716{
717   _mesa_free(v->visinfo);
718   _mesa_free(v);
719}
720
721
722
723/**
724 * Create a new XMesaContext.
725 * \param v  the XMesaVisual
726 * \param share_list  another XMesaContext with which to share display
727 *                    lists or NULL if no sharing is wanted.
728 * \return an XMesaContext or NULL if error.
729 */
730PUBLIC
731XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
732{
733   static GLboolean firstTime = GL_TRUE;
734   struct pipe_winsys *winsys;
735   struct pipe_screen *screen;
736   struct pipe_context *pipe;
737   XMesaContext c;
738   GLcontext *mesaCtx;
739   uint pf;
740
741   if (firstTime) {
742      pipe_mutex_init(_xmesa_lock);
743      firstTime = GL_FALSE;
744   }
745
746   /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */
747   c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
748   if (!c)
749      return NULL;
750
751   pf = choose_pixel_format(v);
752   assert(pf);
753
754   c->xm_visual = v;
755   c->xm_buffer = NULL;   /* set later by XMesaMakeCurrent */
756
757   /* XXX: create once per Xlib Display.
758    */
759   winsys = xmesa_create_pipe_winsys();
760   if (winsys == NULL)
761      goto fail;
762
763   /* XXX: create once per Xlib Display.
764    */
765   screen = xmesa_create_pipe_screen( winsys );
766   if (screen == NULL)
767      goto fail;
768
769   pipe = xmesa_create_pipe_context( screen,
770                                     (void *)c );
771   if (pipe == NULL)
772      goto fail;
773
774   c->st = st_create_context(pipe,
775                             &v->mesa_visual,
776                             share_list ? share_list->st : NULL);
777   if (c->st == NULL)
778      goto fail;
779
780   mesaCtx = c->st->ctx;
781   c->st->ctx->DriverCtx = c;
782
783#if 00
784   _mesa_enable_sw_extensions(mesaCtx);
785   _mesa_enable_1_3_extensions(mesaCtx);
786   _mesa_enable_1_4_extensions(mesaCtx);
787   _mesa_enable_1_5_extensions(mesaCtx);
788   _mesa_enable_2_0_extensions(mesaCtx);
789#endif
790
791   return c;
792
793 fail:
794   if (c->st)
795      st_destroy_context(c->st);
796   else if (pipe)
797      pipe->destroy(pipe);
798
799   if (screen)
800      screen->destroy( screen );
801
802   if (winsys)
803      winsys->destroy( winsys );
804
805   FREE(c);
806   return NULL;
807}
808
809
810
811PUBLIC
812void XMesaDestroyContext( XMesaContext c )
813{
814   st_destroy_context(c->st);
815
816   /* FIXME: We should destroy the screen here, but if we do so, surfaces may
817    * outlive it, causing segfaults
818   struct pipe_screen *screen = c->st->pipe->screen;
819   screen->destroy(screen);
820   */
821
822   _mesa_free(c);
823}
824
825
826
827/**
828 * Private function for creating an XMesaBuffer which corresponds to an
829 * X window or pixmap.
830 * \param v  the window's XMesaVisual
831 * \param w  the window we're wrapping
832 * \return  new XMesaBuffer or NULL if error
833 */
834PUBLIC XMesaBuffer
835XMesaCreateWindowBuffer(XMesaVisual v, Window w)
836{
837   XWindowAttributes attr;
838   XMesaBuffer b;
839   Colormap cmap;
840   int depth;
841
842   assert(v);
843   assert(w);
844
845   /* Check that window depth matches visual depth */
846   XGetWindowAttributes( v->display, w, &attr );
847   depth = attr.depth;
848   if (v->visinfo->depth != depth) {
849      _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
850                    v->visinfo->depth, depth);
851      return NULL;
852   }
853
854   /* Find colormap */
855   if (attr.colormap) {
856      cmap = attr.colormap;
857   }
858   else {
859      _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w);
860      /* this is weird, a window w/out a colormap!? */
861      /* OK, let's just allocate a new one and hope for the best */
862      cmap = XCreateColormap(v->display, w, attr.visual, AllocNone);
863   }
864
865   b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap);
866   if (!b)
867      return NULL;
868
869   if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode,
870                                      (Drawable) w, cmap )) {
871      xmesa_free_buffer(b);
872      return NULL;
873   }
874
875   return b;
876}
877
878
879
880/**
881 * Create a new XMesaBuffer from an X pixmap.
882 *
883 * \param v    the XMesaVisual
884 * \param p    the pixmap
885 * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or
886 *             \c GLX_DIRECT_COLOR visual for the pixmap
887 * \returns new XMesaBuffer or NULL if error
888 */
889PUBLIC XMesaBuffer
890XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap)
891{
892   XMesaBuffer b;
893
894   assert(v);
895
896   b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
897   if (!b)
898      return NULL;
899
900   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
901				     (Drawable) p, cmap)) {
902      xmesa_free_buffer(b);
903      return NULL;
904   }
905
906   return b;
907}
908
909
910/**
911 * For GLX_EXT_texture_from_pixmap
912 */
913XMesaBuffer
914XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
915                               Colormap cmap,
916                               int format, int target, int mipmap)
917{
918   GET_CURRENT_CONTEXT(ctx);
919   XMesaBuffer b;
920   GLuint width, height;
921
922   assert(v);
923
924   b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
925   if (!b)
926      return NULL;
927
928   /* get pixmap size, update framebuffer/renderbuffer dims */
929   xmesa_get_window_size(v->display, b, &width, &height);
930   _mesa_resize_framebuffer(NULL, &(b->stfb->Base), width, height);
931
932   if (target == 0) {
933      /* examine dims */
934      if (ctx->Extensions.ARB_texture_non_power_of_two) {
935         target = GLX_TEXTURE_2D_EXT;
936      }
937      else if (   _mesa_bitcount(width)  == 1
938               && _mesa_bitcount(height) == 1) {
939         /* power of two size */
940         if (height == 1) {
941            target = GLX_TEXTURE_1D_EXT;
942         }
943         else {
944            target = GLX_TEXTURE_2D_EXT;
945         }
946      }
947      else if (ctx->Extensions.NV_texture_rectangle) {
948         target = GLX_TEXTURE_RECTANGLE_EXT;
949      }
950      else {
951         /* non power of two textures not supported */
952         XMesaDestroyBuffer(b);
953         return 0;
954      }
955   }
956
957   b->TextureTarget = target;
958   b->TextureFormat = format;
959   b->TextureMipmap = mipmap;
960
961   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
962				     (Drawable) p, cmap)) {
963      xmesa_free_buffer(b);
964      return NULL;
965   }
966
967   return b;
968}
969
970
971
972XMesaBuffer
973XMesaCreatePBuffer(XMesaVisual v, Colormap cmap,
974                   unsigned int width, unsigned int height)
975{
976   Window root;
977   Drawable drawable;  /* X Pixmap Drawable */
978   XMesaBuffer b;
979
980   /* allocate pixmap for front buffer */
981   root = RootWindow( v->display, v->visinfo->screen );
982   drawable = XCreatePixmap(v->display, root, width, height,
983                            v->visinfo->depth);
984   if (!drawable)
985      return NULL;
986
987   b = create_xmesa_buffer(drawable, PBUFFER, v, cmap);
988   if (!b)
989      return NULL;
990
991   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
992				     drawable, cmap)) {
993      xmesa_free_buffer(b);
994      return NULL;
995   }
996
997   return b;
998}
999
1000
1001
1002/*
1003 * Deallocate an XMesaBuffer structure and all related info.
1004 */
1005PUBLIC void
1006XMesaDestroyBuffer(XMesaBuffer b)
1007{
1008   xmesa_free_buffer(b);
1009}
1010
1011
1012/**
1013 * Query the current window size and update the corresponding GLframebuffer
1014 * and all attached renderbuffers.
1015 * Called when:
1016 *  1. the first time a buffer is bound to a context.
1017 *  2. SwapBuffers.  XXX probabaly from xm_flush_frontbuffer() too...
1018 * Note: it's possible (and legal) for xmctx to be NULL.  That can happen
1019 * when resizing a buffer when no rendering context is bound.
1020 */
1021void
1022xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer)
1023{
1024   GLuint width, height;
1025   xmesa_get_window_size(drawBuffer->xm_visual->display, drawBuffer, &width, &height);
1026   st_resize_framebuffer(drawBuffer->stfb, width, height);
1027}
1028
1029
1030
1031
1032/*
1033 * Bind buffer b to context c and make c the current rendering context.
1034 */
1035PUBLIC
1036GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
1037                             XMesaBuffer readBuffer )
1038{
1039   if (c) {
1040      if (!drawBuffer || !readBuffer)
1041         return GL_FALSE;  /* must specify buffers! */
1042
1043#if 0
1044      /* XXX restore this optimization */
1045      if (&(c->mesa) == _mesa_get_current_context()
1046          && c->mesa.DrawBuffer == &drawBuffer->mesa_buffer
1047          && c->mesa.ReadBuffer == &readBuffer->mesa_buffer
1048          && xmesa_buffer(c->mesa.DrawBuffer)->wasCurrent) {
1049         /* same context and buffer, do nothing */
1050         return GL_TRUE;
1051      }
1052#endif
1053
1054      c->xm_buffer = drawBuffer;
1055
1056      /* Call this periodically to detect when the user has begun using
1057       * GL rendering from multiple threads.
1058       */
1059      _glapi_check_multithread();
1060
1061      st_make_current(c->st, drawBuffer->stfb, readBuffer->stfb);
1062
1063      xmesa_check_and_update_buffer_size(c, drawBuffer);
1064      if (readBuffer != drawBuffer)
1065         xmesa_check_and_update_buffer_size(c, readBuffer);
1066
1067      /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
1068      drawBuffer->wasCurrent = GL_TRUE;
1069   }
1070   else {
1071      /* Detach */
1072      st_make_current( NULL, NULL, NULL );
1073   }
1074   return GL_TRUE;
1075}
1076
1077
1078/*
1079 * Unbind the context c from its buffer.
1080 */
1081GLboolean XMesaUnbindContext( XMesaContext c )
1082{
1083   /* A no-op for XFree86 integration purposes */
1084   return GL_TRUE;
1085}
1086
1087
1088XMesaContext XMesaGetCurrentContext( void )
1089{
1090   GET_CURRENT_CONTEXT(ctx);
1091   if (ctx) {
1092      XMesaContext xmesa = xmesa_context(ctx);
1093      return xmesa;
1094   }
1095   else {
1096      return 0;
1097   }
1098}
1099
1100
1101
1102
1103
1104
1105/*
1106 * Copy the back buffer to the front buffer.  If there's no back buffer
1107 * this is a no-op.
1108 */
1109PUBLIC
1110void XMesaSwapBuffers( XMesaBuffer b )
1111{
1112   struct pipe_surface *surf;
1113
1114   /* If we're swapping the buffer associated with the current context
1115    * we have to flush any pending rendering commands first.
1116    */
1117   st_notify_swapbuffers(b->stfb);
1118
1119   surf = st_get_framebuffer_surface(b->stfb, ST_SURFACE_BACK_LEFT);
1120   if (surf) {
1121      xmesa_display_surface(b, surf);
1122//	 xmesa_display_surface(b, surf);
1123   }
1124
1125   xmesa_check_and_update_buffer_size(NULL, b);
1126}
1127
1128
1129
1130/*
1131 * Copy sub-region of back buffer to front buffer
1132 */
1133void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
1134{
1135   struct pipe_surface *surf_front
1136      = st_get_framebuffer_surface(b->stfb, ST_SURFACE_FRONT_LEFT);
1137   struct pipe_surface *surf_back
1138      = st_get_framebuffer_surface(b->stfb, ST_SURFACE_BACK_LEFT);
1139   struct pipe_context *pipe = NULL; /* XXX fix */
1140
1141   if (!surf_front || !surf_back)
1142      return;
1143
1144   pipe->surface_copy(pipe,
1145                      FALSE,
1146                      surf_front, x, y,  /* dest */
1147                      surf_back, x, y,   /* src */
1148                      width, height);
1149}
1150
1151
1152
1153void XMesaFlush( XMesaContext c )
1154{
1155   if (c && c->xm_visual->display) {
1156      st_finish(c->st);
1157      XSync( c->xm_visual->display, False );
1158   }
1159}
1160
1161
1162
1163
1164
1165XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d )
1166{
1167   XMesaBuffer b;
1168   for (b=XMesaBufferList; b; b=b->Next) {
1169      if (b->drawable == d && b->xm_visual->display == dpy) {
1170         return b;
1171      }
1172   }
1173   return NULL;
1174}
1175
1176
1177/**
1178 * Free/destroy all XMesaBuffers associated with given display.
1179 */
1180void xmesa_destroy_buffers_on_display(Display *dpy)
1181{
1182   XMesaBuffer b, next;
1183   for (b = XMesaBufferList; b; b = next) {
1184      next = b->Next;
1185      if (b->xm_visual->display == dpy) {
1186         xmesa_free_buffer(b);
1187      }
1188   }
1189}
1190
1191
1192/*
1193 * Look for XMesaBuffers whose X window has been destroyed.
1194 * Deallocate any such XMesaBuffers.
1195 */
1196void XMesaGarbageCollect( void )
1197{
1198   XMesaBuffer b, next;
1199   for (b=XMesaBufferList; b; b=next) {
1200      next = b->Next;
1201      if (b->xm_visual &&
1202          b->xm_visual->display &&
1203          b->drawable &&
1204          b->type == WINDOW) {
1205         XSync(b->xm_visual->display, False);
1206         if (!window_exists( b->xm_visual->display, b->drawable )) {
1207            /* found a dead window, free the ancillary info */
1208            XMesaDestroyBuffer( b );
1209         }
1210      }
1211   }
1212}
1213
1214
1215
1216
1217PUBLIC void
1218XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer,
1219                  const int *attrib_list)
1220{
1221}
1222
1223
1224
1225PUBLIC void
1226XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer)
1227{
1228}
1229
1230