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