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