• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * 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 <stdio.h>
57 #include "xm_api.h"
58 #include "xm_st.h"
59 
60 #include "pipe/p_context.h"
61 #include "pipe/p_defines.h"
62 #include "pipe/p_screen.h"
63 #include "pipe/p_state.h"
64 
65 #include "util/u_atomic.h"
66 #include "util/u_inlines.h"
67 
68 #include "hud/hud_context.h"
69 
70 #include "xm_public.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  */
78 static struct xm_driver driver;
79 static struct st_api *stapi;
80 
81 /* Default strict invalidate to false.  This means we will not call
82  * XGetGeometry after every swapbuffers, which allows swapbuffers to
83  * remain asynchronous.  For apps running at 100fps with synchronous
84  * swapping, a 10% boost is typical.  For gears, I see closer to 20%
85  * speedup.
86  *
87  * Note that the work of copying data on swapbuffers doesn't disappear
88  * - this change just allows the X server to execute the PutImage
89  * asynchronously without us effectively blocked until its completion.
90  *
91  * This speeds up even llvmpipe's threaded rasterization as the
92  * swapbuffers operation was a large part of the serial component of
93  * an llvmpipe frame.
94  *
95  * The downside of this is correctness - applications which don't call
96  * glViewport on window resizes will get incorrect rendering.  A
97  * better solution would be to have per-frame but asynchronous
98  * invalidation.  Xcb almost looks as if it could provide this, but
99  * the API doesn't seem to quite be there.
100  */
101 boolean xmesa_strict_invalidate = FALSE;
102 
xmesa_set_driver(const struct xm_driver * templ)103 void xmesa_set_driver( const struct xm_driver *templ )
104 {
105    driver = *templ;
106    stapi = driver.create_st_api();
107 
108    xmesa_strict_invalidate =
109       debug_get_bool_option("XMESA_STRICT_INVALIDATE", FALSE);
110 }
111 
112 
113 static int
xmesa_get_param(struct st_manager * smapi,enum st_manager_param param)114 xmesa_get_param(struct st_manager *smapi,
115                 enum st_manager_param param)
116 {
117    switch(param) {
118    case ST_MANAGER_BROKEN_INVALIDATE:
119       return !xmesa_strict_invalidate;
120    default:
121       return 0;
122    }
123 }
124 
125 /* linked list of XMesaDisplay hooks per display */
126 typedef struct _XMesaExtDisplayInfo {
127    struct _XMesaExtDisplayInfo *next;
128    Display *display;
129    struct xmesa_display mesaDisplay;
130 } XMesaExtDisplayInfo;
131 
132 typedef struct _XMesaExtInfo {
133    XMesaExtDisplayInfo *head;
134    int ndisplays;
135 } XMesaExtInfo;
136 
137 static XMesaExtInfo MesaExtInfo;
138 
139 /* hook to delete XMesaDisplay on XDestroyDisplay */
140 extern void
xmesa_close_display(Display * display)141 xmesa_close_display(Display *display)
142 {
143    XMesaExtDisplayInfo *info, *prev;
144 
145    /* These assertions are not valid since screen creation can fail and result
146     * in an empty list
147    assert(MesaExtInfo.ndisplays > 0);
148    assert(MesaExtInfo.head);
149    */
150 
151    _XLockMutex(_Xglobal_lock);
152    /* first find display */
153    prev = NULL;
154    for (info = MesaExtInfo.head; info; info = info->next) {
155       if (info->display == display) {
156          prev = info;
157          break;
158       }
159    }
160 
161    if (info == NULL) {
162       /* no display found */
163       _XUnlockMutex(_Xglobal_lock);
164       return;
165    }
166 
167    /* remove display entry from list */
168    if (prev != MesaExtInfo.head) {
169       prev->next = info->next;
170    } else {
171       MesaExtInfo.head = info->next;
172    }
173    MesaExtInfo.ndisplays--;
174 
175    _XUnlockMutex(_Xglobal_lock);
176 
177    /* don't forget to clean up mesaDisplay */
178    XMesaDisplay xmdpy = &info->mesaDisplay;
179 
180    /**
181     * XXX: Don't destroy the screens here, since there may still
182     * be some dangling screen pointers that are used after this point
183     * if (xmdpy->screen) {
184     *    xmdpy->screen->destroy(xmdpy->screen);
185     * }
186     */
187 
188    if (xmdpy->smapi->destroy)
189       xmdpy->smapi->destroy(xmdpy->smapi);
190    free(xmdpy->smapi);
191 
192    XFree((char *) info);
193 }
194 
195 static XMesaDisplay
xmesa_init_display(Display * display)196 xmesa_init_display( Display *display )
197 {
198    static mtx_t init_mutex = _MTX_INITIALIZER_NP;
199    XMesaDisplay xmdpy;
200    XMesaExtDisplayInfo *info;
201 
202    if (display == NULL) {
203       return NULL;
204    }
205 
206    mtx_lock(&init_mutex);
207 
208    /* Look for XMesaDisplay which corresponds to this display */
209    info = MesaExtInfo.head;
210    while(info) {
211       if (info->display == display) {
212          /* Found it */
213          mtx_unlock(&init_mutex);
214          return  &info->mesaDisplay;
215       }
216       info = info->next;
217    }
218 
219    /* Not found.  Create new XMesaDisplay */
220    /* first allocate X-related resources and hook destroy callback */
221 
222    /* allocate mesa display info */
223    info = (XMesaExtDisplayInfo *) Xmalloc(sizeof(XMesaExtDisplayInfo));
224    if (info == NULL) {
225       mtx_unlock(&init_mutex);
226       return NULL;
227    }
228    info->display = display;
229 
230    xmdpy = &info->mesaDisplay; /* to be filled out below */
231    xmdpy->display = display;
232    xmdpy->pipe = NULL;
233 
234    xmdpy->smapi = CALLOC_STRUCT(st_manager);
235    if (!xmdpy->smapi) {
236       Xfree(info);
237       mtx_unlock(&init_mutex);
238       return NULL;
239    }
240 
241    xmdpy->screen = driver.create_pipe_screen(display);
242    if (!xmdpy->screen) {
243       free(xmdpy->smapi);
244       Xfree(info);
245       mtx_unlock(&init_mutex);
246       return NULL;
247    }
248 
249    /* At this point, both smapi and screen are known to be valid */
250    xmdpy->smapi->screen = xmdpy->screen;
251    xmdpy->smapi->get_param = xmesa_get_param;
252    (void) mtx_init(&xmdpy->mutex, mtx_plain);
253 
254    /* chain to the list of displays */
255    _XLockMutex(_Xglobal_lock);
256    info->next = MesaExtInfo.head;
257    MesaExtInfo.head = info;
258    MesaExtInfo.ndisplays++;
259    _XUnlockMutex(_Xglobal_lock);
260 
261    mtx_unlock(&init_mutex);
262 
263    return xmdpy;
264 }
265 
266 
267 /**********************************************************************/
268 /*****                     X Utility Functions                    *****/
269 /**********************************************************************/
270 
271 
272 /**
273  * Return the host's byte order as LSBFirst or MSBFirst ala X.
274  */
host_byte_order(void)275 static int host_byte_order( void )
276 {
277    int i = 1;
278    char *cptr = (char *) &i;
279    return (*cptr==1) ? LSBFirst : MSBFirst;
280 }
281 
282 
283 
284 
285 /**
286  * Return the true number of bits per pixel for XImages.
287  * For example, if we request a 24-bit deep visual we may actually need/get
288  * 32bpp XImages.  This function returns the appropriate bpp.
289  * Input:  dpy - the X display
290  *         visinfo - desribes the visual to be used for XImages
291  * Return:  true number of bits per pixel for XImages
292  */
293 static int
bits_per_pixel(XMesaVisual xmv)294 bits_per_pixel( XMesaVisual xmv )
295 {
296    Display *dpy = xmv->display;
297    XVisualInfo * visinfo = xmv->visinfo;
298    XImage *img;
299    int bitsPerPixel;
300    /* Create a temporary XImage */
301    img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
302 		       ZPixmap, 0,           /*format, offset*/
303 		       malloc(8),    /*data*/
304 		       1, 1,                 /*width, height*/
305 		       32,                   /*bitmap_pad*/
306 		       0                     /*bytes_per_line*/
307                      );
308    assert(img);
309    /* grab the bits/pixel value */
310    bitsPerPixel = img->bits_per_pixel;
311    /* free the XImage */
312    free( img->data );
313    img->data = NULL;
314    XDestroyImage( img );
315    return bitsPerPixel;
316 }
317 
318 
319 
320 /*
321  * Determine if a given X window ID is valid (window exists).
322  * Do this by calling XGetWindowAttributes() for the window and
323  * checking if we catch an X error.
324  * Input:  dpy - the display
325  *         win - the window to check for existence
326  * Return:  GL_TRUE - window exists
327  *          GL_FALSE - window doesn't exist
328  */
329 static GLboolean WindowExistsFlag;
330 
window_exists_err_handler(Display * dpy,XErrorEvent * xerr)331 static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr )
332 {
333    (void) dpy;
334    if (xerr->error_code == BadWindow) {
335       WindowExistsFlag = GL_FALSE;
336    }
337    return 0;
338 }
339 
window_exists(Display * dpy,Window win)340 static GLboolean window_exists( Display *dpy, Window win )
341 {
342    XWindowAttributes wa;
343    int (*old_handler)( Display*, XErrorEvent* );
344    WindowExistsFlag = GL_TRUE;
345    old_handler = XSetErrorHandler(window_exists_err_handler);
346    XGetWindowAttributes( dpy, win, &wa ); /* dummy request */
347    XSetErrorHandler(old_handler);
348    return WindowExistsFlag;
349 }
350 
351 static Status
get_drawable_size(Display * dpy,Drawable d,uint * width,uint * height)352 get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height )
353 {
354    Window root;
355    Status stat;
356    int xpos, ypos;
357    unsigned int w, h, bw, depth;
358    stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
359    *width = w;
360    *height = h;
361    return stat;
362 }
363 
364 
365 /**
366  * Return the size of the window (or pixmap) that corresponds to the
367  * given XMesaBuffer.
368  * \param width  returns width in pixels
369  * \param height  returns height in pixels
370  */
371 void
xmesa_get_window_size(Display * dpy,XMesaBuffer b,GLuint * width,GLuint * height)372 xmesa_get_window_size(Display *dpy, XMesaBuffer b,
373                       GLuint *width, GLuint *height)
374 {
375    XMesaDisplay xmdpy = xmesa_init_display(dpy);
376    Status stat;
377 
378    mtx_lock(&xmdpy->mutex);
379    stat = get_drawable_size(dpy, b->ws.drawable, width, height);
380    mtx_unlock(&xmdpy->mutex);
381 
382    if (!stat) {
383       /* probably querying a window that's recently been destroyed */
384       _mesa_warning(NULL, "XGetGeometry failed!\n");
385       *width = *height = 1;
386    }
387 }
388 
389 #define GET_REDMASK(__v)        __v->mesa_visual.redMask
390 #define GET_GREENMASK(__v)      __v->mesa_visual.greenMask
391 #define GET_BLUEMASK(__v)       __v->mesa_visual.blueMask
392 
393 
394 /**
395  * Choose the pixel format for the given visual.
396  * This will tell the gallium driver how to pack pixel data into
397  * drawing surfaces.
398  */
399 static GLuint
choose_pixel_format(XMesaVisual v)400 choose_pixel_format(XMesaVisual v)
401 {
402    boolean native_byte_order = (host_byte_order() ==
403                                 ImageByteOrder(v->display));
404 
405    if (   GET_REDMASK(v)   == 0x0000ff
406        && GET_GREENMASK(v) == 0x00ff00
407        && GET_BLUEMASK(v)  == 0xff0000
408        && v->BitsPerPixel == 32) {
409       if (native_byte_order) {
410          /* no byteswapping needed */
411          return PIPE_FORMAT_RGBA8888_UNORM;
412       }
413       else {
414          return PIPE_FORMAT_ABGR8888_UNORM;
415       }
416    }
417    else if (   GET_REDMASK(v)   == 0xff0000
418             && GET_GREENMASK(v) == 0x00ff00
419             && GET_BLUEMASK(v)  == 0x0000ff
420             && v->BitsPerPixel == 32) {
421       if (native_byte_order) {
422          /* no byteswapping needed */
423          return PIPE_FORMAT_BGRA8888_UNORM;
424       }
425       else {
426          return PIPE_FORMAT_ARGB8888_UNORM;
427       }
428    }
429    else if (   GET_REDMASK(v)   == 0x0000ff00
430             && GET_GREENMASK(v) == 0x00ff0000
431             && GET_BLUEMASK(v)  == 0xff000000
432             && v->BitsPerPixel == 32) {
433       if (native_byte_order) {
434          /* no byteswapping needed */
435          return PIPE_FORMAT_ARGB8888_UNORM;
436       }
437       else {
438          return PIPE_FORMAT_BGRA8888_UNORM;
439       }
440    }
441    else if (   GET_REDMASK(v)   == 0xf800
442             && GET_GREENMASK(v) == 0x07e0
443             && GET_BLUEMASK(v)  == 0x001f
444             && native_byte_order
445             && v->BitsPerPixel == 16) {
446       /* 5-6-5 RGB */
447       return PIPE_FORMAT_B5G6R5_UNORM;
448    }
449 
450    return PIPE_FORMAT_NONE;
451 }
452 
453 
454 /**
455  * Choose a depth/stencil format that satisfies the given depth and
456  * stencil sizes.
457  */
458 static enum pipe_format
choose_depth_stencil_format(XMesaDisplay xmdpy,int depth,int stencil,int sample_count)459 choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil,
460                             int sample_count)
461 {
462    const enum pipe_texture_target target = PIPE_TEXTURE_2D;
463    const unsigned tex_usage = PIPE_BIND_DEPTH_STENCIL;
464    enum pipe_format formats[8], fmt;
465    int count, i;
466 
467    count = 0;
468 
469    if (depth <= 16 && stencil == 0) {
470       formats[count++] = PIPE_FORMAT_Z16_UNORM;
471    }
472    if (depth <= 24 && stencil == 0) {
473       formats[count++] = PIPE_FORMAT_X8Z24_UNORM;
474       formats[count++] = PIPE_FORMAT_Z24X8_UNORM;
475    }
476    if (depth <= 24 && stencil <= 8) {
477       formats[count++] = PIPE_FORMAT_S8_UINT_Z24_UNORM;
478       formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_UINT;
479    }
480    if (depth <= 32 && stencil == 0) {
481       formats[count++] = PIPE_FORMAT_Z32_UNORM;
482    }
483 
484    fmt = PIPE_FORMAT_NONE;
485    for (i = 0; i < count; i++) {
486       if (xmdpy->screen->is_format_supported(xmdpy->screen, formats[i],
487                                              target, sample_count,
488                                              tex_usage)) {
489          fmt = formats[i];
490          break;
491       }
492    }
493 
494    return fmt;
495 }
496 
497 
498 
499 /**********************************************************************/
500 /*****                Linked list of XMesaBuffers                 *****/
501 /**********************************************************************/
502 
503 static XMesaBuffer XMesaBufferList = NULL;
504 
505 
506 /**
507  * Allocate a new XMesaBuffer object which corresponds to the given drawable.
508  * Note that XMesaBuffer is derived from struct gl_framebuffer.
509  * The new XMesaBuffer will not have any size (Width=Height=0).
510  *
511  * \param d  the corresponding X drawable (window or pixmap)
512  * \param type  either WINDOW, PIXMAP or PBUFFER, describing d
513  * \param vis  the buffer's visual
514  * \param cmap  the window's colormap, if known.
515  * \return new XMesaBuffer or NULL if any problem
516  */
517 static XMesaBuffer
create_xmesa_buffer(Drawable d,BufferType type,XMesaVisual vis,Colormap cmap)518 create_xmesa_buffer(Drawable d, BufferType type,
519                     XMesaVisual vis, Colormap cmap)
520 {
521    XMesaDisplay xmdpy = xmesa_init_display(vis->display);
522    XMesaBuffer b;
523 
524    assert(type == WINDOW || type == PIXMAP || type == PBUFFER);
525 
526    if (!xmdpy)
527       return NULL;
528 
529    b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer);
530    if (!b)
531       return NULL;
532 
533    b->ws.drawable = d;
534    b->ws.visual = vis->visinfo->visual;
535    b->ws.depth = vis->visinfo->depth;
536 
537    b->xm_visual = vis;
538    b->type = type;
539    b->cmap = cmap;
540 
541    get_drawable_size(vis->display, d, &b->width, &b->height);
542 
543    /*
544     * Create framebuffer, but we'll plug in our own renderbuffers below.
545     */
546    b->stfb = xmesa_create_st_framebuffer(xmdpy, b);
547 
548    /* GLX_EXT_texture_from_pixmap */
549    b->TextureTarget = 0;
550    b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT;
551    b->TextureMipmap = 0;
552 
553    /* insert buffer into linked list */
554    b->Next = XMesaBufferList;
555    XMesaBufferList = b;
556 
557    return b;
558 }
559 
560 
561 /**
562  * Find an XMesaBuffer by matching X display and colormap but NOT matching
563  * the notThis buffer.
564  */
565 XMesaBuffer
xmesa_find_buffer(Display * dpy,Colormap cmap,XMesaBuffer notThis)566 xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis)
567 {
568    XMesaBuffer b;
569    for (b = XMesaBufferList; b; b = b->Next) {
570       if (b->xm_visual->display == dpy &&
571           b->cmap == cmap &&
572           b != notThis) {
573          return b;
574       }
575    }
576    return NULL;
577 }
578 
579 
580 /**
581  * Remove buffer from linked list, delete if no longer referenced.
582  */
583 static void
xmesa_free_buffer(XMesaBuffer buffer)584 xmesa_free_buffer(XMesaBuffer buffer)
585 {
586    XMesaBuffer prev = NULL, b;
587 
588    for (b = XMesaBufferList; b; b = b->Next) {
589       if (b == buffer) {
590          /* unlink buffer from list */
591          if (prev)
592             prev->Next = buffer->Next;
593          else
594             XMesaBufferList = buffer->Next;
595 
596          /* Since the X window for the XMesaBuffer is going away, we don't
597           * want to dereference this pointer in the future.
598           */
599          b->ws.drawable = 0;
600 
601          /* Notify the st manager that the associated framebuffer interface
602           * object is no longer valid.
603           */
604          stapi->destroy_drawable(stapi, buffer->stfb);
605 
606          /* XXX we should move the buffer to a delete-pending list and destroy
607           * the buffer until it is no longer current.
608           */
609          xmesa_destroy_st_framebuffer(buffer->stfb);
610 
611          free(buffer);
612 
613          return;
614       }
615       /* continue search */
616       prev = b;
617    }
618    /* buffer not found in XMesaBufferList */
619    _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n");
620 }
621 
622 
623 
624 /**********************************************************************/
625 /*****                   Misc Private Functions                   *****/
626 /**********************************************************************/
627 
628 
629 /**
630  * When a context is bound for the first time, we can finally finish
631  * initializing the context's visual and buffer information.
632  * \param v  the XMesaVisual to initialize
633  * \param b  the XMesaBuffer to initialize (may be NULL)
634  * \param rgb_flag  TRUE = RGBA mode, FALSE = color index mode
635  * \param window  the window/pixmap we're rendering into
636  * \param cmap  the colormap associated with the window/pixmap
637  * \return GL_TRUE=success, GL_FALSE=failure
638  */
639 static GLboolean
initialize_visual_and_buffer(XMesaVisual v,XMesaBuffer b,GLboolean rgb_flag,Drawable window,Colormap cmap)640 initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
641                              GLboolean rgb_flag, Drawable window,
642                              Colormap cmap)
643 {
644    assert(!b || b->xm_visual == v);
645 
646    /* Save true bits/pixel */
647    v->BitsPerPixel = bits_per_pixel(v);
648    assert(v->BitsPerPixel > 0);
649 
650    if (rgb_flag == GL_FALSE) {
651       /* COLOR-INDEXED WINDOW: not supported*/
652       return GL_FALSE;
653    }
654    else {
655       /* RGB WINDOW:
656        * We support RGB rendering into almost any kind of visual.
657        */
658       const int xclass = v->visualType;
659       if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) {
660 	 _mesa_warning(NULL,
661             "XMesa: RGB mode rendering not supported in given visual.\n");
662 	 return GL_FALSE;
663       }
664       v->mesa_visual.indexBits = 0;
665 
666       if (v->BitsPerPixel == 32) {
667          /* We use XImages for all front/back buffers.  If an X Window or
668           * X Pixmap is 32bpp, there's no guarantee that the alpha channel
669           * will be preserved.  For XImages we're in luck.
670           */
671          v->mesa_visual.alphaBits = 8;
672       }
673    }
674 
675    /*
676     * If MESA_INFO env var is set print out some debugging info
677     * which can help Brian figure out what's going on when a user
678     * reports bugs.
679     */
680    if (getenv("MESA_INFO")) {
681       printf("X/Mesa visual = %p\n", (void *) v);
682       printf("X/Mesa level = %d\n", v->mesa_visual.level);
683       printf("X/Mesa depth = %d\n", v->visinfo->depth);
684       printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel);
685    }
686 
687    return GL_TRUE;
688 }
689 
690 
691 
692 #define NUM_VISUAL_TYPES   6
693 
694 /**
695  * Convert an X visual type to a GLX visual type.
696  *
697  * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
698  *        to be converted.
699  * \return If \c visualType is a valid X visual type, a GLX visual type will
700  *         be returned.  Otherwise \c GLX_NONE will be returned.
701  *
702  * \note
703  * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
704  * DRI CVS tree.
705  */
706 static GLint
xmesa_convert_from_x_visual_type(int visualType)707 xmesa_convert_from_x_visual_type( int visualType )
708 {
709     static const int glx_visual_types[ NUM_VISUAL_TYPES ] = {
710 	GLX_STATIC_GRAY,  GLX_GRAY_SCALE,
711 	GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
712 	GLX_TRUE_COLOR,   GLX_DIRECT_COLOR
713     };
714 
715     return ( (unsigned) visualType < NUM_VISUAL_TYPES )
716 	? glx_visual_types[ visualType ] : GLX_NONE;
717 }
718 
719 
720 /**********************************************************************/
721 /*****                       Public Functions                     *****/
722 /**********************************************************************/
723 
724 
725 /*
726  * Create a new X/Mesa visual.
727  * Input:  display - X11 display
728  *         visinfo - an XVisualInfo pointer
729  *         rgb_flag - GL_TRUE = RGB mode,
730  *                    GL_FALSE = color index mode
731  *         alpha_flag - alpha buffer requested?
732  *         db_flag - GL_TRUE = double-buffered,
733  *                   GL_FALSE = single buffered
734  *         stereo_flag - stereo visual?
735  *         ximage_flag - GL_TRUE = use an XImage for back buffer,
736  *                       GL_FALSE = use an off-screen pixmap for back buffer
737  *         depth_size - requested bits/depth values, or zero
738  *         stencil_size - requested bits/stencil values, or zero
739  *         accum_red_size - requested bits/red accum values, or zero
740  *         accum_green_size - requested bits/green accum values, or zero
741  *         accum_blue_size - requested bits/blue accum values, or zero
742  *         accum_alpha_size - requested bits/alpha accum values, or zero
743  *         num_samples - number of samples/pixel if multisampling, or zero
744  *         level - visual level, usually 0
745  *         visualCaveat - ala the GLX extension, usually GLX_NONE
746  * Return;  a new XMesaVisual or 0 if error.
747  */
748 PUBLIC
XMesaCreateVisual(Display * display,XVisualInfo * visinfo,GLboolean rgb_flag,GLboolean alpha_flag,GLboolean db_flag,GLboolean stereo_flag,GLboolean ximage_flag,GLint depth_size,GLint stencil_size,GLint accum_red_size,GLint accum_green_size,GLint accum_blue_size,GLint accum_alpha_size,GLint num_samples,GLint level,GLint visualCaveat)749 XMesaVisual XMesaCreateVisual( Display *display,
750                                XVisualInfo * visinfo,
751                                GLboolean rgb_flag,
752                                GLboolean alpha_flag,
753                                GLboolean db_flag,
754                                GLboolean stereo_flag,
755                                GLboolean ximage_flag,
756                                GLint depth_size,
757                                GLint stencil_size,
758                                GLint accum_red_size,
759                                GLint accum_green_size,
760                                GLint accum_blue_size,
761                                GLint accum_alpha_size,
762                                GLint num_samples,
763                                GLint level,
764                                GLint visualCaveat )
765 {
766    XMesaDisplay xmdpy = xmesa_init_display(display);
767    XMesaVisual v;
768    GLint red_bits, green_bits, blue_bits, alpha_bits;
769 
770    if (!xmdpy)
771       return NULL;
772 
773    /* For debugging only */
774    if (getenv("MESA_XSYNC")) {
775       /* This makes debugging X easier.
776        * In your debugger, set a breakpoint on _XError to stop when an
777        * X protocol error is generated.
778        */
779       XSynchronize( display, 1 );
780    }
781 
782    v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual);
783    if (!v) {
784       return NULL;
785    }
786 
787    v->display = display;
788 
789    /* Save a copy of the XVisualInfo struct because the user may Xfree()
790     * the struct but we may need some of the information contained in it
791     * at a later time.
792     */
793    v->visinfo = malloc(sizeof(*visinfo));
794    if (!v->visinfo) {
795       free(v);
796       return NULL;
797    }
798    memcpy(v->visinfo, visinfo, sizeof(*visinfo));
799 
800    v->ximage_flag = ximage_flag;
801 
802    v->mesa_visual.redMask = visinfo->red_mask;
803    v->mesa_visual.greenMask = visinfo->green_mask;
804    v->mesa_visual.blueMask = visinfo->blue_mask;
805    v->visualID = visinfo->visualid;
806    v->screen = visinfo->screen;
807 
808 #if !(defined(__cplusplus) || defined(c_plusplus))
809    v->visualType = xmesa_convert_from_x_visual_type(visinfo->class);
810 #else
811    v->visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
812 #endif
813 
814    v->mesa_visual.visualRating = visualCaveat;
815 
816    if (alpha_flag)
817       v->mesa_visual.alphaBits = 8;
818 
819    (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 );
820 
821    {
822       const int xclass = v->visualType;
823       if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
824          red_bits   = _mesa_bitcount(GET_REDMASK(v));
825          green_bits = _mesa_bitcount(GET_GREENMASK(v));
826          blue_bits  = _mesa_bitcount(GET_BLUEMASK(v));
827       }
828       else {
829          /* this is an approximation */
830          int depth;
831          depth = v->visinfo->depth;
832          red_bits = depth / 3;
833          depth -= red_bits;
834          green_bits = depth / 2;
835          depth -= green_bits;
836          blue_bits = depth;
837          alpha_bits = 0;
838          assert( red_bits + green_bits + blue_bits == v->visinfo->depth );
839       }
840       alpha_bits = v->mesa_visual.alphaBits;
841    }
842 
843    /* initialize visual */
844    {
845       struct gl_config *vis = &v->mesa_visual;
846 
847       vis->rgbMode          = GL_TRUE;
848       vis->doubleBufferMode = db_flag;
849       vis->stereoMode       = stereo_flag;
850 
851       vis->redBits          = red_bits;
852       vis->greenBits        = green_bits;
853       vis->blueBits         = blue_bits;
854       vis->alphaBits        = alpha_bits;
855       vis->rgbBits          = red_bits + green_bits + blue_bits;
856 
857       vis->indexBits      = 0;
858       vis->depthBits      = depth_size;
859       vis->stencilBits    = stencil_size;
860 
861       vis->accumRedBits   = accum_red_size;
862       vis->accumGreenBits = accum_green_size;
863       vis->accumBlueBits  = accum_blue_size;
864       vis->accumAlphaBits = accum_alpha_size;
865 
866       vis->haveAccumBuffer   = accum_red_size > 0;
867       vis->haveDepthBuffer   = depth_size > 0;
868       vis->haveStencilBuffer = stencil_size > 0;
869 
870       vis->numAuxBuffers = 0;
871       vis->level = 0;
872       vis->sampleBuffers = num_samples > 1;
873       vis->samples = num_samples;
874    }
875 
876    v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
877    if (db_flag)
878       v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
879    if (stereo_flag) {
880       v->stvis.buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
881       if (db_flag)
882          v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
883    }
884 
885    v->stvis.color_format = choose_pixel_format(v);
886 
887    /* Check format support at requested num_samples (for multisample) */
888    if (!xmdpy->screen->is_format_supported(xmdpy->screen,
889                                            v->stvis.color_format,
890                                            PIPE_TEXTURE_2D, num_samples,
891                                            PIPE_BIND_RENDER_TARGET))
892       v->stvis.color_format = PIPE_FORMAT_NONE;
893 
894    if (v->stvis.color_format == PIPE_FORMAT_NONE) {
895       free(v->visinfo);
896       free(v);
897       return NULL;
898    }
899 
900    v->stvis.depth_stencil_format =
901       choose_depth_stencil_format(xmdpy, depth_size, stencil_size,
902                                   num_samples);
903 
904    v->stvis.accum_format = (accum_red_size +
905          accum_green_size + accum_blue_size + accum_alpha_size) ?
906       PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
907 
908    v->stvis.samples = num_samples;
909    v->stvis.render_buffer = ST_ATTACHMENT_INVALID;
910 
911    /* XXX minor hack */
912    v->mesa_visual.level = level;
913    return v;
914 }
915 
916 
917 PUBLIC
XMesaDestroyVisual(XMesaVisual v)918 void XMesaDestroyVisual( XMesaVisual v )
919 {
920    free(v->visinfo);
921    free(v);
922 }
923 
924 
925 /**
926  * Return the informative name.
927  */
928 const char *
xmesa_get_name(void)929 xmesa_get_name(void)
930 {
931    return stapi->name;
932 }
933 
934 
935 /**
936  * Do per-display initializations.
937  */
938 int
xmesa_init(Display * display)939 xmesa_init( Display *display )
940 {
941    return xmesa_init_display(display) ? 0 : 1;
942 }
943 
944 
945 /**
946  * Create a new XMesaContext.
947  * \param v  the XMesaVisual
948  * \param share_list  another XMesaContext with which to share display
949  *                    lists or NULL if no sharing is wanted.
950  * \return an XMesaContext or NULL if error.
951  */
952 PUBLIC
XMesaCreateContext(XMesaVisual v,XMesaContext share_list,GLuint major,GLuint minor,GLuint profileMask,GLuint contextFlags)953 XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list,
954                                  GLuint major, GLuint minor,
955                                  GLuint profileMask, GLuint contextFlags)
956 {
957    XMesaDisplay xmdpy = xmesa_init_display(v->display);
958    struct st_context_attribs attribs;
959    enum st_context_error ctx_err = 0;
960    XMesaContext c;
961 
962    if (!xmdpy)
963       goto no_xmesa_context;
964 
965    /* Note: the XMesaContext contains a Mesa struct gl_context struct (inheritance) */
966    c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
967    if (!c)
968       goto no_xmesa_context;
969 
970    c->xm_visual = v;
971    c->xm_buffer = NULL;   /* set later by XMesaMakeCurrent */
972    c->xm_read_buffer = NULL;
973 
974    memset(&attribs, 0, sizeof(attribs));
975    attribs.visual = v->stvis;
976    attribs.major = major;
977    attribs.minor = minor;
978    if (contextFlags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
979       attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
980    if (contextFlags & GLX_CONTEXT_DEBUG_BIT_ARB)
981       attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
982    if (contextFlags & GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB)
983       attribs.flags |= ST_CONTEXT_FLAG_ROBUST_ACCESS;
984 
985    switch (profileMask) {
986    case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
987       /* There are no profiles before OpenGL 3.2.  The
988        * GLX_ARB_create_context_profile spec says:
989        *
990        *     "If the requested OpenGL version is less than 3.2,
991        *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
992        *     of the context is determined solely by the requested version."
993        */
994       if (major > 3 || (major == 3 && minor >= 2)) {
995          attribs.profile = ST_PROFILE_OPENGL_CORE;
996          break;
997       }
998       /* fall-through */
999    case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
1000       /*
1001        * The spec also says:
1002        *
1003        *     "If version 3.1 is requested, the context returned may implement
1004        *     any of the following versions:
1005        *
1006        *       * Version 3.1. The GL_ARB_compatibility extension may or may not
1007        *         be implemented, as determined by the implementation.
1008        *       * The core profile of version 3.2 or greater."
1009        *
1010        * and because Mesa doesn't support GL_ARB_compatibility, the only chance to
1011        * honour a 3.1 context is through core profile.
1012        */
1013       if (major == 3 && minor == 1) {
1014          attribs.profile = ST_PROFILE_OPENGL_CORE;
1015       } else {
1016          attribs.profile = ST_PROFILE_DEFAULT;
1017       }
1018       break;
1019    case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
1020       if (major >= 2) {
1021          attribs.profile = ST_PROFILE_OPENGL_ES2;
1022       } else {
1023          attribs.profile = ST_PROFILE_OPENGL_ES1;
1024       }
1025       break;
1026    default:
1027       assert(0);
1028       goto no_st;
1029    }
1030 
1031    c->st = stapi->create_context(stapi, xmdpy->smapi, &attribs,
1032          &ctx_err, (share_list) ? share_list->st : NULL);
1033    if (c->st == NULL)
1034       goto no_st;
1035 
1036    c->st->st_manager_private = (void *) c;
1037 
1038    c->hud = hud_create(c->st->cso_context, NULL);
1039 
1040    return c;
1041 
1042 no_st:
1043    free(c);
1044 no_xmesa_context:
1045    return NULL;
1046 }
1047 
1048 
1049 
1050 PUBLIC
XMesaDestroyContext(XMesaContext c)1051 void XMesaDestroyContext( XMesaContext c )
1052 {
1053    if (c->hud) {
1054       hud_destroy(c->hud, NULL);
1055    }
1056 
1057    c->st->destroy(c->st);
1058 
1059    /* FIXME: We should destroy the screen here, but if we do so, surfaces may
1060     * outlive it, causing segfaults
1061    struct pipe_screen *screen = c->st->pipe->screen;
1062    screen->destroy(screen);
1063    */
1064 
1065    free(c);
1066 }
1067 
1068 
1069 
1070 /**
1071  * Private function for creating an XMesaBuffer which corresponds to an
1072  * X window or pixmap.
1073  * \param v  the window's XMesaVisual
1074  * \param w  the window we're wrapping
1075  * \return  new XMesaBuffer or NULL if error
1076  */
1077 PUBLIC XMesaBuffer
XMesaCreateWindowBuffer(XMesaVisual v,Window w)1078 XMesaCreateWindowBuffer(XMesaVisual v, Window w)
1079 {
1080    XWindowAttributes attr;
1081    XMesaBuffer b;
1082    Colormap cmap;
1083    int depth;
1084 
1085    assert(v);
1086    assert(w);
1087 
1088    /* Check that window depth matches visual depth */
1089    XGetWindowAttributes( v->display, w, &attr );
1090    depth = attr.depth;
1091    if (v->visinfo->depth != depth) {
1092       _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
1093                     v->visinfo->depth, depth);
1094       return NULL;
1095    }
1096 
1097    /* Find colormap */
1098    if (attr.colormap) {
1099       cmap = attr.colormap;
1100    }
1101    else {
1102       _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w);
1103       /* this is weird, a window w/out a colormap!? */
1104       /* OK, let's just allocate a new one and hope for the best */
1105       cmap = XCreateColormap(v->display, w, attr.visual, AllocNone);
1106    }
1107 
1108    b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap);
1109    if (!b)
1110       return NULL;
1111 
1112    if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode,
1113                                       (Drawable) w, cmap )) {
1114       xmesa_free_buffer(b);
1115       return NULL;
1116    }
1117 
1118    return b;
1119 }
1120 
1121 
1122 
1123 /**
1124  * Create a new XMesaBuffer from an X pixmap.
1125  *
1126  * \param v    the XMesaVisual
1127  * \param p    the pixmap
1128  * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or
1129  *             \c GLX_DIRECT_COLOR visual for the pixmap
1130  * \returns new XMesaBuffer or NULL if error
1131  */
1132 PUBLIC XMesaBuffer
XMesaCreatePixmapBuffer(XMesaVisual v,Pixmap p,Colormap cmap)1133 XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap)
1134 {
1135    XMesaBuffer b;
1136 
1137    assert(v);
1138 
1139    b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
1140    if (!b)
1141       return NULL;
1142 
1143    if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1144 				     (Drawable) p, cmap)) {
1145       xmesa_free_buffer(b);
1146       return NULL;
1147    }
1148 
1149    return b;
1150 }
1151 
1152 
1153 /**
1154  * For GLX_EXT_texture_from_pixmap
1155  */
1156 XMesaBuffer
XMesaCreatePixmapTextureBuffer(XMesaVisual v,Pixmap p,Colormap cmap,int format,int target,int mipmap)1157 XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
1158                                Colormap cmap,
1159                                int format, int target, int mipmap)
1160 {
1161    GET_CURRENT_CONTEXT(ctx);
1162    XMesaBuffer b;
1163 
1164    assert(v);
1165 
1166    b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
1167    if (!b)
1168       return NULL;
1169 
1170    /* get pixmap size */
1171    xmesa_get_window_size(v->display, b, &b->width, &b->height);
1172 
1173    if (target == 0) {
1174       /* examine dims */
1175       if (ctx->Extensions.ARB_texture_non_power_of_two) {
1176          target = GLX_TEXTURE_2D_EXT;
1177       }
1178       else if (   _mesa_bitcount(b->width)  == 1
1179                && _mesa_bitcount(b->height) == 1) {
1180          /* power of two size */
1181          if (b->height == 1) {
1182             target = GLX_TEXTURE_1D_EXT;
1183          }
1184          else {
1185             target = GLX_TEXTURE_2D_EXT;
1186          }
1187       }
1188       else if (ctx->Extensions.NV_texture_rectangle) {
1189          target = GLX_TEXTURE_RECTANGLE_EXT;
1190       }
1191       else {
1192          /* non power of two textures not supported */
1193          XMesaDestroyBuffer(b);
1194          return 0;
1195       }
1196    }
1197 
1198    b->TextureTarget = target;
1199    b->TextureFormat = format;
1200    b->TextureMipmap = mipmap;
1201 
1202    if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1203 				     (Drawable) p, cmap)) {
1204       xmesa_free_buffer(b);
1205       return NULL;
1206    }
1207 
1208    return b;
1209 }
1210 
1211 
1212 
1213 XMesaBuffer
XMesaCreatePBuffer(XMesaVisual v,Colormap cmap,unsigned int width,unsigned int height)1214 XMesaCreatePBuffer(XMesaVisual v, Colormap cmap,
1215                    unsigned int width, unsigned int height)
1216 {
1217    Window root;
1218    Drawable drawable;  /* X Pixmap Drawable */
1219    XMesaBuffer b;
1220 
1221    /* allocate pixmap for front buffer */
1222    root = RootWindow( v->display, v->visinfo->screen );
1223    drawable = XCreatePixmap(v->display, root, width, height,
1224                             v->visinfo->depth);
1225    if (!drawable)
1226       return NULL;
1227 
1228    b = create_xmesa_buffer(drawable, PBUFFER, v, cmap);
1229    if (!b)
1230       return NULL;
1231 
1232    if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1233 				     drawable, cmap)) {
1234       xmesa_free_buffer(b);
1235       return NULL;
1236    }
1237 
1238    return b;
1239 }
1240 
1241 
1242 
1243 /*
1244  * Deallocate an XMesaBuffer structure and all related info.
1245  */
1246 PUBLIC void
XMesaDestroyBuffer(XMesaBuffer b)1247 XMesaDestroyBuffer(XMesaBuffer b)
1248 {
1249    xmesa_free_buffer(b);
1250 }
1251 
1252 
1253 /**
1254  * Notify the binding context to validate the buffer.
1255  */
1256 void
xmesa_notify_invalid_buffer(XMesaBuffer b)1257 xmesa_notify_invalid_buffer(XMesaBuffer b)
1258 {
1259    p_atomic_inc(&b->stfb->stamp);
1260 }
1261 
1262 
1263 /**
1264  * Query the current drawable size and notify the binding context.
1265  */
1266 void
xmesa_check_buffer_size(XMesaBuffer b)1267 xmesa_check_buffer_size(XMesaBuffer b)
1268 {
1269    GLuint old_width, old_height;
1270 
1271    if (b->type == PBUFFER)
1272       return;
1273 
1274    old_width = b->width;
1275    old_height = b->height;
1276 
1277    xmesa_get_window_size(b->xm_visual->display, b, &b->width, &b->height);
1278 
1279    if (b->width != old_width || b->height != old_height)
1280       xmesa_notify_invalid_buffer(b);
1281 }
1282 
1283 
1284 /*
1285  * Bind buffer b to context c and make c the current rendering context.
1286  */
1287 PUBLIC
XMesaMakeCurrent2(XMesaContext c,XMesaBuffer drawBuffer,XMesaBuffer readBuffer)1288 GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
1289                              XMesaBuffer readBuffer )
1290 {
1291    XMesaContext old_ctx = XMesaGetCurrentContext();
1292 
1293    if (old_ctx && old_ctx != c) {
1294       XMesaFlush(old_ctx);
1295       old_ctx->xm_buffer = NULL;
1296       old_ctx->xm_read_buffer = NULL;
1297    }
1298 
1299    if (c) {
1300       if (!drawBuffer || !readBuffer)
1301          return GL_FALSE;  /* must specify buffers! */
1302 
1303       if (c == old_ctx &&
1304 	  c->xm_buffer == drawBuffer &&
1305 	  c->xm_read_buffer == readBuffer)
1306 	 return GL_TRUE;
1307 
1308       xmesa_check_buffer_size(drawBuffer);
1309       if (readBuffer != drawBuffer)
1310          xmesa_check_buffer_size(readBuffer);
1311 
1312       c->xm_buffer = drawBuffer;
1313       c->xm_read_buffer = readBuffer;
1314 
1315       stapi->make_current(stapi, c->st, drawBuffer->stfb, readBuffer->stfb);
1316 
1317       /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
1318       drawBuffer->wasCurrent = GL_TRUE;
1319    }
1320    else {
1321       /* Detach */
1322       stapi->make_current(stapi, NULL, NULL, NULL);
1323 
1324    }
1325    return GL_TRUE;
1326 }
1327 
1328 
1329 /*
1330  * Unbind the context c from its buffer.
1331  */
XMesaUnbindContext(XMesaContext c)1332 GLboolean XMesaUnbindContext( XMesaContext c )
1333 {
1334    /* A no-op for XFree86 integration purposes */
1335    return GL_TRUE;
1336 }
1337 
1338 
XMesaGetCurrentContext(void)1339 XMesaContext XMesaGetCurrentContext( void )
1340 {
1341    struct st_context_iface *st = stapi->get_current(stapi);
1342    return (XMesaContext) (st) ? st->st_manager_private : NULL;
1343 }
1344 
1345 
1346 
1347 /**
1348  * Swap front and back color buffers and have winsys display front buffer.
1349  * If there's no front color buffer no swap actually occurs.
1350  */
1351 PUBLIC
XMesaSwapBuffers(XMesaBuffer b)1352 void XMesaSwapBuffers( XMesaBuffer b )
1353 {
1354    XMesaContext xmctx = XMesaGetCurrentContext();
1355 
1356    /* Need to draw HUD before flushing */
1357    if (xmctx && xmctx->hud) {
1358       struct pipe_resource *back =
1359          xmesa_get_framebuffer_resource(b->stfb, ST_ATTACHMENT_BACK_LEFT);
1360       hud_run(xmctx->hud, NULL, back);
1361    }
1362 
1363    if (xmctx && xmctx->xm_buffer == b) {
1364       xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL);
1365    }
1366 
1367    xmesa_swap_st_framebuffer(b->stfb);
1368 }
1369 
1370 
1371 
1372 /*
1373  * Copy sub-region of back buffer to front buffer
1374  */
XMesaCopySubBuffer(XMesaBuffer b,int x,int y,int width,int height)1375 void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
1376 {
1377    XMesaContext xmctx = XMesaGetCurrentContext();
1378 
1379    xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL);
1380 
1381    xmesa_copy_st_framebuffer(b->stfb,
1382          ST_ATTACHMENT_BACK_LEFT, ST_ATTACHMENT_FRONT_LEFT,
1383          x, b->height - y - height, width, height);
1384 }
1385 
1386 
1387 
XMesaFlush(XMesaContext c)1388 void XMesaFlush( XMesaContext c )
1389 {
1390    if (c && c->xm_visual->display) {
1391       XMesaDisplay xmdpy = xmesa_init_display(c->xm_visual->display);
1392       struct pipe_fence_handle *fence = NULL;
1393 
1394       c->st->flush(c->st, ST_FLUSH_FRONT, &fence);
1395       if (fence) {
1396          xmdpy->screen->fence_finish(xmdpy->screen, NULL, fence,
1397                                      PIPE_TIMEOUT_INFINITE);
1398          xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL);
1399       }
1400       XFlush( c->xm_visual->display );
1401    }
1402 }
1403 
1404 
1405 
1406 
1407 
XMesaFindBuffer(Display * dpy,Drawable d)1408 XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d )
1409 {
1410    XMesaBuffer b;
1411    for (b = XMesaBufferList; b; b = b->Next) {
1412       if (b->ws.drawable == d && b->xm_visual->display == dpy) {
1413          return b;
1414       }
1415    }
1416    return NULL;
1417 }
1418 
1419 
1420 /**
1421  * Free/destroy all XMesaBuffers associated with given display.
1422  */
xmesa_destroy_buffers_on_display(Display * dpy)1423 void xmesa_destroy_buffers_on_display(Display *dpy)
1424 {
1425    XMesaBuffer b, next;
1426    for (b = XMesaBufferList; b; b = next) {
1427       next = b->Next;
1428       if (b->xm_visual->display == dpy) {
1429          xmesa_free_buffer(b);
1430          /* delete head of list? */
1431          if (XMesaBufferList == b) {
1432             XMesaBufferList = next;
1433          }
1434       }
1435    }
1436 }
1437 
1438 
1439 /*
1440  * Look for XMesaBuffers whose X window has been destroyed.
1441  * Deallocate any such XMesaBuffers.
1442  */
XMesaGarbageCollect(void)1443 void XMesaGarbageCollect( void )
1444 {
1445    XMesaBuffer b, next;
1446    for (b=XMesaBufferList; b; b=next) {
1447       next = b->Next;
1448       if (b->xm_visual &&
1449           b->xm_visual->display &&
1450           b->ws.drawable &&
1451           b->type == WINDOW) {
1452          XSync(b->xm_visual->display, False);
1453          if (!window_exists( b->xm_visual->display, b->ws.drawable )) {
1454             /* found a dead window, free the ancillary info */
1455             XMesaDestroyBuffer( b );
1456          }
1457       }
1458    }
1459 }
1460 
1461 
xmesa_attachment_type(int glx_attachment)1462 static enum st_attachment_type xmesa_attachment_type(int glx_attachment)
1463 {
1464    switch(glx_attachment) {
1465       case GLX_FRONT_LEFT_EXT:
1466          return ST_ATTACHMENT_FRONT_LEFT;
1467       case GLX_FRONT_RIGHT_EXT:
1468          return ST_ATTACHMENT_FRONT_RIGHT;
1469       case GLX_BACK_LEFT_EXT:
1470          return ST_ATTACHMENT_BACK_LEFT;
1471       case GLX_BACK_RIGHT_EXT:
1472          return ST_ATTACHMENT_BACK_RIGHT;
1473       default:
1474          assert(0);
1475          return ST_ATTACHMENT_FRONT_LEFT;
1476    }
1477 }
1478 
1479 
1480 PUBLIC void
XMesaBindTexImage(Display * dpy,XMesaBuffer drawable,int buffer,const int * attrib_list)1481 XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer,
1482                   const int *attrib_list)
1483 {
1484    struct st_context_iface *st = stapi->get_current(stapi);
1485    struct st_framebuffer_iface* stfbi = drawable->stfb;
1486    struct pipe_resource *res;
1487    int x, y, w, h;
1488    enum st_attachment_type st_attachment = xmesa_attachment_type(buffer);
1489 
1490    x = 0;
1491    y = 0;
1492    w = drawable->width;
1493    h = drawable->height;
1494 
1495    /* We need to validate our attachments before using them,
1496     * in case the texture doesn't exist yet. */
1497    xmesa_st_framebuffer_validate_textures(stfbi, w, h, 1 << st_attachment);
1498    res = xmesa_get_attachment(stfbi, st_attachment);
1499 
1500    if (res) {
1501       struct pipe_context* pipe = xmesa_get_context(stfbi);
1502       enum pipe_format internal_format = res->format;
1503       struct pipe_transfer *tex_xfer;
1504       char *map;
1505       int line, byte_width;
1506       XImage *img;
1507 
1508       internal_format = choose_pixel_format(drawable->xm_visual);
1509 
1510       map = pipe_transfer_map(pipe, res,
1511                               0, 0,    /* level, layer */
1512                               PIPE_TRANSFER_WRITE,
1513                               x, y,
1514                               w, h, &tex_xfer);
1515       if (!map)
1516          return;
1517 
1518       /* Grab the XImage that we want to turn into a texture. */
1519       img = XGetImage(dpy,
1520                       drawable->ws.drawable,
1521                       x, y,
1522                       w, h,
1523                       AllPlanes,
1524                       ZPixmap);
1525 
1526       if (!img) {
1527          pipe_transfer_unmap(pipe, tex_xfer);
1528          return;
1529       }
1530 
1531       /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. */
1532       byte_width = w * ((img->bits_per_pixel + 7) / 8);
1533 
1534       for (line = 0; line < h; line++)
1535          memcpy(&map[line * tex_xfer->stride],
1536                 &img->data[line * img->bytes_per_line],
1537                 byte_width);
1538 
1539       pipe_transfer_unmap(pipe, tex_xfer);
1540 
1541       st->teximage(st,
1542                    ST_TEXTURE_2D,
1543                    0,    /* level */
1544                    internal_format,
1545                    res,
1546                    FALSE /* no mipmap */);
1547 
1548    }
1549 }
1550 
1551 
1552 
1553 PUBLIC void
XMesaReleaseTexImage(Display * dpy,XMesaBuffer drawable,int buffer)1554 XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer)
1555 {
1556 }
1557 
1558 
1559 void
XMesaCopyContext(XMesaContext src,XMesaContext dst,unsigned long mask)1560 XMesaCopyContext(XMesaContext src, XMesaContext dst, unsigned long mask)
1561 {
1562    if (dst->st->copy)
1563       dst->st->copy(dst->st, src->st, mask);
1564 }
1565