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