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