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