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