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