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