0e303d597ab5c3dbca9f2d774dfe0c36c03c69c2
[mesa.git] / src / mesa / pipe / 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. In
52 * Mesa, when byte swapping is needed we use the PF_TRUECOLOR pixel format
53 * and use XPutPixel everywhere except in the implementation of
54 * glClear(GL_COLOR_BUFFER_BIT). We want this function to be fast so
55 * instead of using XPutPixel we "poke" our values after byte-swapping
56 * the clear pixel value if needed.
57 *
58 */
59
60 #ifdef __CYGWIN__
61 #undef WIN32
62 #undef __WIN32__
63 #endif
64
65 #include "glxheader.h"
66 #include "GL/xmesa.h"
67 #include "xmesaP.h"
68 #include "context.h"
69 #include "extensions.h"
70 #include "framebuffer.h"
71 #include "glthread.h"
72 #include "imports.h"
73 #include "macros.h"
74 #include "renderbuffer.h"
75 #include "teximage.h"
76 #include "vbo/vbo.h"
77
78 #include "state_tracker/st_public.h"
79 #include "state_tracker/st_context.h"
80 #include "pipe/softpipe/sp_context.h"
81 #include "pipe/p_defines.h"
82
83 /**
84 * Global X driver lock
85 */
86 _glthread_Mutex _xmesa_lock;
87
88
89
90 /**********************************************************************/
91 /***** X Utility Functions *****/
92 /**********************************************************************/
93
94
95 /**
96 * Return the host's byte order as LSBFirst or MSBFirst ala X.
97 */
98 #ifndef XFree86Server
99 static int host_byte_order( void )
100 {
101 int i = 1;
102 char *cptr = (char *) &i;
103 return (*cptr==1) ? LSBFirst : MSBFirst;
104 }
105 #endif
106
107
108 /**
109 * Check if the X Shared Memory extension is available.
110 * Return: 0 = not available
111 * 1 = shared XImage support available
112 * 2 = shared Pixmap support available also
113 */
114 static int check_for_xshm( XMesaDisplay *display )
115 {
116 #if defined(USE_XSHM) && !defined(XFree86Server)
117 int major, minor, ignore;
118 Bool pixmaps;
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 * Apply gamma correction to an intensity value in [0..max]. Return the
140 * new intensity value.
141 */
142 static GLint
143 gamma_adjust( GLfloat gamma, GLint value, GLint max )
144 {
145 if (gamma == 1.0) {
146 return value;
147 }
148 else {
149 double x = (double) value / (double) max;
150 return IROUND_POS((GLfloat) max * _mesa_pow(x, 1.0F/gamma));
151 }
152 }
153
154
155
156 /**
157 * Return the true number of bits per pixel for XImages.
158 * For example, if we request a 24-bit deep visual we may actually need/get
159 * 32bpp XImages. This function returns the appropriate bpp.
160 * Input: dpy - the X display
161 * visinfo - desribes the visual to be used for XImages
162 * Return: true number of bits per pixel for XImages
163 */
164 static int
165 bits_per_pixel( XMesaVisual xmv )
166 {
167 #ifdef XFree86Server
168 const int depth = xmv->nplanes;
169 int i;
170 assert(depth > 0);
171 for (i = 0; i < screenInfo.numPixmapFormats; i++) {
172 if (screenInfo.formats[i].depth == depth)
173 return screenInfo.formats[i].bitsPerPixel;
174 }
175 return depth; /* should never get here, but this should be safe */
176 #else
177 XMesaDisplay *dpy = xmv->display;
178 XMesaVisualInfo visinfo = xmv->visinfo;
179 XMesaImage *img;
180 int bitsPerPixel;
181 /* Create a temporary XImage */
182 img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
183 ZPixmap, 0, /*format, offset*/
184 (char*) MALLOC(8), /*data*/
185 1, 1, /*width, height*/
186 32, /*bitmap_pad*/
187 0 /*bytes_per_line*/
188 );
189 assert(img);
190 /* grab the bits/pixel value */
191 bitsPerPixel = img->bits_per_pixel;
192 /* free the XImage */
193 _mesa_free( img->data );
194 img->data = NULL;
195 XMesaDestroyImage( img );
196 return bitsPerPixel;
197 #endif
198 }
199
200
201
202 /*
203 * Determine if a given X window ID is valid (window exists).
204 * Do this by calling XGetWindowAttributes() for the window and
205 * checking if we catch an X error.
206 * Input: dpy - the display
207 * win - the window to check for existance
208 * Return: GL_TRUE - window exists
209 * GL_FALSE - window doesn't exist
210 */
211 #ifndef XFree86Server
212 static GLboolean WindowExistsFlag;
213
214 static int window_exists_err_handler( XMesaDisplay* dpy, XErrorEvent* xerr )
215 {
216 (void) dpy;
217 if (xerr->error_code == BadWindow) {
218 WindowExistsFlag = GL_FALSE;
219 }
220 return 0;
221 }
222
223 static GLboolean window_exists( XMesaDisplay *dpy, Window win )
224 {
225 XWindowAttributes wa;
226 int (*old_handler)( XMesaDisplay*, XErrorEvent* );
227 WindowExistsFlag = GL_TRUE;
228 old_handler = XSetErrorHandler(window_exists_err_handler);
229 XGetWindowAttributes( dpy, win, &wa ); /* dummy request */
230 XSetErrorHandler(old_handler);
231 return WindowExistsFlag;
232 }
233
234 static Status
235 get_drawable_size( XMesaDisplay *dpy, Drawable d, GLuint *width, GLuint *height )
236 {
237 Window root;
238 Status stat;
239 int xpos, ypos;
240 unsigned int w, h, bw, depth;
241 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
242 *width = w;
243 *height = h;
244 return stat;
245 }
246 #endif
247
248
249 /**
250 * Return the size of the window (or pixmap) that corresponds to the
251 * given XMesaBuffer.
252 * \param width returns width in pixels
253 * \param height returns height in pixels
254 */
255 void
256 xmesa_get_window_size(XMesaDisplay *dpy, XMesaBuffer b,
257 GLuint *width, GLuint *height)
258 {
259 #ifdef XFree86Server
260 *width = MIN2(b->frontxrb->drawable->width, MAX_WIDTH);
261 *height = MIN2(b->frontxrb->drawable->height, MAX_HEIGHT);
262 #else
263 Status stat;
264
265 _glthread_LOCK_MUTEX(_xmesa_lock);
266 XSync(b->xm_visual->display, 0); /* added for Chromium */
267 stat = get_drawable_size(dpy, b->frontxrb->pixmap, width, height);
268 _glthread_UNLOCK_MUTEX(_xmesa_lock);
269
270 if (!stat) {
271 /* probably querying a window that's recently been destroyed */
272 _mesa_warning(NULL, "XGetGeometry failed!\n");
273 *width = *height = 1;
274 }
275 #endif
276 }
277
278
279
280 /**********************************************************************/
281 /***** Linked list of XMesaBuffers *****/
282 /**********************************************************************/
283
284 XMesaBuffer XMesaBufferList = NULL;
285
286
287 /**
288 * Allocate a new XMesaBuffer object which corresponds to the given drawable.
289 * Note that XMesaBuffer is derived from GLframebuffer.
290 * The new XMesaBuffer will not have any size (Width=Height=0).
291 *
292 * \param d the corresponding X drawable (window or pixmap)
293 * \param type either WINDOW, PIXMAP or PBUFFER, describing d
294 * \param vis the buffer's visual
295 * \param cmap the window's colormap, if known.
296 * \return new XMesaBuffer or NULL if any problem
297 */
298 static XMesaBuffer
299 create_xmesa_buffer(XMesaDrawable d, BufferType type,
300 XMesaVisual vis, XMesaColormap cmap)
301 {
302 XMesaBuffer b;
303 GLframebuffer *fb;
304
305 ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER);
306
307 b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer);
308 if (!b)
309 return NULL;
310
311 b->display = vis->display;
312 b->xm_visual = vis;
313 b->type = type;
314 b->cmap = cmap;
315
316 /*
317 * Create framebuffer, but we'll plug in our own renderbuffers below.
318 */
319 b->stfb = st_create_framebuffer(&vis->mesa_visual, GL_FALSE, (void *) b);
320 fb = &b->stfb->Base;
321
322 fb->Delete = xmesa_delete_framebuffer;
323
324 /*
325 * XXX we want to create surfaces for pipe, not renderbuffers for Mesa.
326 */
327
328 /*
329 * Front renderbuffer
330 */
331 b->frontxrb = xmesa_create_renderbuffer(NULL, 0, &vis->mesa_visual, GL_FALSE);
332 if (!b->frontxrb) {
333 _mesa_free(b);
334 return NULL;
335 }
336 b->frontxrb->Parent = b;
337 b->frontxrb->drawable = d;
338 b->frontxrb->pixmap = (XMesaPixmap) d;
339 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &b->frontxrb->St.Base);
340 #if 0 /* sketch... */
341 {
342 struct pipe_surface *front_surf;
343 front_surf = xmesa_create_front_surface(vis, d);
344 }
345 #endif
346
347 /*
348 * Back renderbuffer
349 */
350 if (vis->mesa_visual.doubleBufferMode) {
351 b->backxrb = xmesa_create_renderbuffer(NULL, 0, &vis->mesa_visual, GL_TRUE);
352 if (!b->backxrb) {
353 /* XXX free front xrb too */
354 _mesa_free(b);
355 return NULL;
356 }
357 b->backxrb->Parent = b;
358 /* determine back buffer implementation */
359 b->db_mode = vis->ximage_flag ? BACK_XIMAGE : BACK_PIXMAP;
360
361 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &b->backxrb->St.Base);
362 }
363
364 /*
365 * Software alpha planes
366 */
367 if (vis->mesa_visual.alphaBits > 0
368 && vis->undithered_pf != PF_8A8B8G8R
369 && vis->undithered_pf != PF_8A8R8G8B) {
370 /* Visual has alpha, but pixel format doesn't support it.
371 * We'll use an alpha renderbuffer wrapper.
372 */
373 b->swAlpha = GL_TRUE;
374 }
375 else {
376 b->swAlpha = GL_FALSE;
377 }
378
379 if (vis->mesa_visual.depthBits > 0 &&
380 vis->mesa_visual.stencilBits > 0) {
381 /* combined depth/stencil */
382 struct gl_renderbuffer *rb
383 = st_new_renderbuffer_fb(GL_DEPTH24_STENCIL8_EXT);
384 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
385 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
386 }
387 else {
388 if (vis->mesa_visual.depthBits > 0) {
389 struct gl_renderbuffer *rb
390 = st_new_renderbuffer_fb(GL_DEPTH_COMPONENT32);
391 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
392 }
393
394 if (vis->mesa_visual.stencilBits > 0) {
395 struct gl_renderbuffer *rb
396 = st_new_renderbuffer_fb(GL_STENCIL_INDEX8_EXT);
397 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
398 }
399 }
400
401 if (vis->mesa_visual.accumRedBits > 0) {
402 struct gl_renderbuffer *rb
403 = st_new_renderbuffer_fb(GL_RGBA16);
404 _mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb);
405 }
406
407
408 /*
409 * Other renderbuffer (depth, stencil, etc)
410 */
411 _mesa_add_soft_renderbuffers(fb,
412 GL_FALSE, /* color */
413 GL_FALSE, /*vis->mesa_visual.haveDepthBuffer,*/
414 GL_FALSE, /* stencil */
415 GL_FALSE, /* accum */
416 b->swAlpha,
417 vis->mesa_visual.numAuxBuffers > 0 );
418
419 /* GLX_EXT_texture_from_pixmap */
420 b->TextureTarget = 0;
421 b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT;
422 b->TextureMipmap = 0;
423
424 /* insert buffer into linked list */
425 b->Next = XMesaBufferList;
426 XMesaBufferList = b;
427
428 return b;
429 }
430
431
432 /**
433 * Find an XMesaBuffer by matching X display and colormap but NOT matching
434 * the notThis buffer.
435 */
436 XMesaBuffer
437 xmesa_find_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis)
438 {
439 XMesaBuffer b;
440 for (b=XMesaBufferList; b; b=b->Next) {
441 if (b->display==dpy && b->cmap==cmap && b!=notThis) {
442 return b;
443 }
444 }
445 return NULL;
446 }
447
448
449 /**
450 * Remove buffer from linked list, delete if no longer referenced.
451 */
452 static void
453 xmesa_free_buffer(XMesaBuffer buffer)
454 {
455 XMesaBuffer prev = NULL, b;
456
457 for (b = XMesaBufferList; b; b = b->Next) {
458 if (b == buffer) {
459 struct gl_framebuffer *fb = &buffer->stfb->Base;
460
461 /* unlink buffer from list */
462 if (prev)
463 prev->Next = buffer->Next;
464 else
465 XMesaBufferList = buffer->Next;
466
467 /* mark as delete pending */
468 fb->DeletePending = GL_TRUE;
469
470 /* Since the X window for the XMesaBuffer is going away, we don't
471 * want to dereference this pointer in the future.
472 */
473 b->frontxrb->drawable = 0;
474
475 /* Unreference. If count = zero we'll really delete the buffer */
476 _mesa_unreference_framebuffer(&fb);
477
478 return;
479 }
480 /* continue search */
481 prev = b;
482 }
483 /* buffer not found in XMesaBufferList */
484 _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n");
485 }
486
487
488 /**
489 * Copy X color table stuff from one XMesaBuffer to another.
490 */
491 static void
492 copy_colortable_info(XMesaBuffer dst, const XMesaBuffer src)
493 {
494 MEMCPY(dst->color_table, src->color_table, sizeof(src->color_table));
495 MEMCPY(dst->pixel_to_r, src->pixel_to_r, sizeof(src->pixel_to_r));
496 MEMCPY(dst->pixel_to_g, src->pixel_to_g, sizeof(src->pixel_to_g));
497 MEMCPY(dst->pixel_to_b, src->pixel_to_b, sizeof(src->pixel_to_b));
498 dst->num_alloced = src->num_alloced;
499 MEMCPY(dst->alloced_colors, src->alloced_colors,
500 sizeof(src->alloced_colors));
501 }
502
503
504
505 /**********************************************************************/
506 /***** Misc Private Functions *****/
507 /**********************************************************************/
508
509
510 /**
511 * A replacement for XAllocColor. This function should never
512 * fail to allocate a color. When XAllocColor fails, we return
513 * the nearest matching color. If we have to allocate many colors
514 * this function isn't too efficient; the XQueryColors() could be
515 * done just once.
516 * Written by Michael Pichler, Brian Paul, Mark Kilgard
517 * Input: dpy - X display
518 * cmap - X colormap
519 * cmapSize - size of colormap
520 * In/Out: color - the XColor struct
521 * Output: exact - 1=exact color match, 0=closest match
522 * alloced - 1=XAlloc worked, 0=XAlloc failed
523 */
524 static void
525 noFaultXAllocColor( int client,
526 XMesaDisplay *dpy,
527 XMesaColormap cmap,
528 int cmapSize,
529 XMesaColor *color,
530 int *exact, int *alloced )
531 {
532 #ifdef XFree86Server
533 Pixel *ppixIn;
534 xrgb *ctable;
535 #else
536 /* we'll try to cache ctable for better remote display performance */
537 static Display *prevDisplay = NULL;
538 static XMesaColormap prevCmap = 0;
539 static int prevCmapSize = 0;
540 static XMesaColor *ctable = NULL;
541 #endif
542 XMesaColor subColor;
543 int i, bestmatch;
544 double mindist; /* 3*2^16^2 exceeds long int precision. */
545
546 (void) client;
547
548 /* First try just using XAllocColor. */
549 #ifdef XFree86Server
550 if (AllocColor(cmap,
551 &color->red, &color->green, &color->blue,
552 &color->pixel,
553 client) == Success)
554 #else
555 if (XAllocColor(dpy, cmap, color))
556 #endif
557 {
558 *exact = 1;
559 *alloced = 1;
560 return;
561 }
562
563 /* Alloc failed, search for closest match */
564
565 /* Retrieve color table entries. */
566 /* XXX alloca candidate. */
567 #ifdef XFree86Server
568 ppixIn = (Pixel *) MALLOC(cmapSize * sizeof(Pixel));
569 ctable = (xrgb *) MALLOC(cmapSize * sizeof(xrgb));
570 for (i = 0; i < cmapSize; i++) {
571 ppixIn[i] = i;
572 }
573 QueryColors(cmap, cmapSize, ppixIn, ctable);
574 #else
575 if (prevDisplay != dpy || prevCmap != cmap
576 || prevCmapSize != cmapSize || !ctable) {
577 /* free previously cached color table */
578 if (ctable)
579 _mesa_free(ctable);
580 /* Get the color table from X */
581 ctable = (XMesaColor *) MALLOC(cmapSize * sizeof(XMesaColor));
582 assert(ctable);
583 for (i = 0; i < cmapSize; i++) {
584 ctable[i].pixel = i;
585 }
586 XQueryColors(dpy, cmap, ctable, cmapSize);
587 prevDisplay = dpy;
588 prevCmap = cmap;
589 prevCmapSize = cmapSize;
590 }
591 #endif
592
593 /* Find best match. */
594 bestmatch = -1;
595 mindist = 0.0;
596 for (i = 0; i < cmapSize; i++) {
597 double dr = 0.30 * ((double) color->red - (double) ctable[i].red);
598 double dg = 0.59 * ((double) color->green - (double) ctable[i].green);
599 double db = 0.11 * ((double) color->blue - (double) ctable[i].blue);
600 double dist = dr * dr + dg * dg + db * db;
601 if (bestmatch < 0 || dist < mindist) {
602 bestmatch = i;
603 mindist = dist;
604 }
605 }
606
607 /* Return result. */
608 subColor.red = ctable[bestmatch].red;
609 subColor.green = ctable[bestmatch].green;
610 subColor.blue = ctable[bestmatch].blue;
611 /* Try to allocate the closest match color. This should only
612 * fail if the cell is read/write. Otherwise, we're incrementing
613 * the cell's reference count.
614 */
615 #ifdef XFree86Server
616 if (AllocColor(cmap,
617 &subColor.red, &subColor.green, &subColor.blue,
618 &subColor.pixel,
619 client) == Success) {
620 #else
621 if (XAllocColor(dpy, cmap, &subColor)) {
622 #endif
623 *alloced = 1;
624 }
625 else {
626 /* do this to work around a problem reported by Frank Ortega */
627 subColor.pixel = (unsigned long) bestmatch;
628 subColor.red = ctable[bestmatch].red;
629 subColor.green = ctable[bestmatch].green;
630 subColor.blue = ctable[bestmatch].blue;
631 subColor.flags = DoRed | DoGreen | DoBlue;
632 *alloced = 0;
633 }
634 #ifdef XFree86Server
635 _mesa_free(ppixIn);
636 _mesa_free(ctable);
637 #else
638 /* don't free table, save it for next time */
639 #endif
640
641 *color = subColor;
642 *exact = 0;
643 }
644
645
646
647 /**
648 * Do setup for PF_GRAYSCALE pixel format.
649 * Note that buffer may be NULL.
650 */
651 static GLboolean
652 setup_grayscale(int client, XMesaVisual v,
653 XMesaBuffer buffer, XMesaColormap cmap)
654 {
655 if (GET_VISUAL_DEPTH(v)<4 || GET_VISUAL_DEPTH(v)>16) {
656 return GL_FALSE;
657 }
658
659 if (buffer) {
660 XMesaBuffer prevBuffer;
661
662 if (!cmap) {
663 return GL_FALSE;
664 }
665
666 prevBuffer = xmesa_find_buffer(v->display, cmap, buffer);
667 if (prevBuffer &&
668 (buffer->xm_visual->mesa_visual.rgbMode ==
669 prevBuffer->xm_visual->mesa_visual.rgbMode)) {
670 /* Copy colormap stuff from previous XMesaBuffer which uses same
671 * X colormap. Do this to avoid time spent in noFaultXAllocColor.
672 */
673 copy_colortable_info(buffer, prevBuffer);
674 }
675 else {
676 /* Allocate 256 shades of gray */
677 int gray;
678 int colorsfailed = 0;
679 for (gray=0;gray<256;gray++) {
680 GLint r = gamma_adjust( v->RedGamma, gray, 255 );
681 GLint g = gamma_adjust( v->GreenGamma, gray, 255 );
682 GLint b = gamma_adjust( v->BlueGamma, gray, 255 );
683 int exact, alloced;
684 XMesaColor xcol;
685 xcol.red = (r << 8) | r;
686 xcol.green = (g << 8) | g;
687 xcol.blue = (b << 8) | b;
688 noFaultXAllocColor( client, v->display,
689 cmap, GET_COLORMAP_SIZE(v),
690 &xcol, &exact, &alloced );
691 if (!exact) {
692 colorsfailed++;
693 }
694 if (alloced) {
695 assert(buffer->num_alloced<256);
696 buffer->alloced_colors[buffer->num_alloced] = xcol.pixel;
697 buffer->num_alloced++;
698 }
699
700 /*OLD
701 assert(gray < 576);
702 buffer->color_table[gray*3+0] = xcol.pixel;
703 buffer->color_table[gray*3+1] = xcol.pixel;
704 buffer->color_table[gray*3+2] = xcol.pixel;
705 assert(xcol.pixel < 65536);
706 buffer->pixel_to_r[xcol.pixel] = gray * 30 / 100;
707 buffer->pixel_to_g[xcol.pixel] = gray * 59 / 100;
708 buffer->pixel_to_b[xcol.pixel] = gray * 11 / 100;
709 */
710 buffer->color_table[gray] = xcol.pixel;
711 assert(xcol.pixel < 65536);
712 buffer->pixel_to_r[xcol.pixel] = gray;
713 buffer->pixel_to_g[xcol.pixel] = gray;
714 buffer->pixel_to_b[xcol.pixel] = gray;
715 }
716
717 if (colorsfailed && _mesa_getenv("MESA_DEBUG")) {
718 _mesa_warning(NULL,
719 "Note: %d out of 256 needed colors do not match exactly.\n",
720 colorsfailed );
721 }
722 }
723 }
724
725 v->dithered_pf = PF_Grayscale;
726 v->undithered_pf = PF_Grayscale;
727 return GL_TRUE;
728 }
729
730
731
732 /**
733 * Setup RGB rendering for a window with a PseudoColor, StaticColor,
734 * or 8-bit TrueColor visual visual. We try to allocate a palette of 225
735 * colors (5 red, 9 green, 5 blue) and dither to approximate a 24-bit RGB
736 * color. While this function was originally designed just for 8-bit
737 * visuals, it has also proven to work from 4-bit up to 16-bit visuals.
738 * Dithering code contributed by Bob Mercier.
739 */
740 static GLboolean
741 setup_dithered_color(int client, XMesaVisual v,
742 XMesaBuffer buffer, XMesaColormap cmap)
743 {
744 if (GET_VISUAL_DEPTH(v)<4 || GET_VISUAL_DEPTH(v)>16) {
745 return GL_FALSE;
746 }
747
748 if (buffer) {
749 XMesaBuffer prevBuffer;
750
751 if (!cmap) {
752 return GL_FALSE;
753 }
754
755 prevBuffer = xmesa_find_buffer(v->display, cmap, buffer);
756 if (prevBuffer &&
757 (buffer->xm_visual->mesa_visual.rgbMode ==
758 prevBuffer->xm_visual->mesa_visual.rgbMode)) {
759 /* Copy colormap stuff from previous, matching XMesaBuffer.
760 * Do this to avoid time spent in noFaultXAllocColor.
761 */
762 copy_colortable_info(buffer, prevBuffer);
763 }
764 else {
765 /* Allocate X colors and initialize color_table[], red_table[], etc */
766 int r, g, b, i;
767 int colorsfailed = 0;
768 for (r = 0; r < DITH_R; r++) {
769 for (g = 0; g < DITH_G; g++) {
770 for (b = 0; b < DITH_B; b++) {
771 XMesaColor xcol;
772 int exact, alloced;
773 xcol.red =gamma_adjust(v->RedGamma, r*65535/(DITH_R-1),65535);
774 xcol.green=gamma_adjust(v->GreenGamma, g*65535/(DITH_G-1),65535);
775 xcol.blue =gamma_adjust(v->BlueGamma, b*65535/(DITH_B-1),65535);
776 noFaultXAllocColor( client, v->display,
777 cmap, GET_COLORMAP_SIZE(v),
778 &xcol, &exact, &alloced );
779 if (!exact) {
780 colorsfailed++;
781 }
782 if (alloced) {
783 assert(buffer->num_alloced<256);
784 buffer->alloced_colors[buffer->num_alloced] = xcol.pixel;
785 buffer->num_alloced++;
786 }
787 i = DITH_MIX( r, g, b );
788 assert(i < 576);
789 buffer->color_table[i] = xcol.pixel;
790 assert(xcol.pixel < 65536);
791 buffer->pixel_to_r[xcol.pixel] = r * 255 / (DITH_R-1);
792 buffer->pixel_to_g[xcol.pixel] = g * 255 / (DITH_G-1);
793 buffer->pixel_to_b[xcol.pixel] = b * 255 / (DITH_B-1);
794 }
795 }
796 }
797
798 if (colorsfailed && _mesa_getenv("MESA_DEBUG")) {
799 _mesa_warning(NULL,
800 "Note: %d out of %d needed colors do not match exactly.\n",
801 colorsfailed, DITH_R * DITH_G * DITH_B );
802 }
803 }
804 }
805
806 v->dithered_pf = PF_Dither;
807 v->undithered_pf = PF_Lookup;
808 return GL_TRUE;
809 }
810
811
812 /**
813 * Setup RGB rendering for a window with a True/DirectColor visual.
814 */
815 static void
816 setup_truecolor(XMesaVisual v, XMesaBuffer buffer, XMesaColormap cmap)
817 {
818 unsigned long rmask, gmask, bmask;
819 (void) buffer;
820 (void) cmap;
821
822 /* Compute red multiplier (mask) and bit shift */
823 v->rshift = 0;
824 rmask = GET_REDMASK(v);
825 while ((rmask & 1)==0) {
826 v->rshift++;
827 rmask = rmask >> 1;
828 }
829
830 /* Compute green multiplier (mask) and bit shift */
831 v->gshift = 0;
832 gmask = GET_GREENMASK(v);
833 while ((gmask & 1)==0) {
834 v->gshift++;
835 gmask = gmask >> 1;
836 }
837
838 /* Compute blue multiplier (mask) and bit shift */
839 v->bshift = 0;
840 bmask = GET_BLUEMASK(v);
841 while ((bmask & 1)==0) {
842 v->bshift++;
843 bmask = bmask >> 1;
844 }
845
846 /*
847 * Compute component-to-pixel lookup tables and dithering kernel
848 */
849 {
850 static GLubyte kernel[16] = {
851 0*16, 8*16, 2*16, 10*16,
852 12*16, 4*16, 14*16, 6*16,
853 3*16, 11*16, 1*16, 9*16,
854 15*16, 7*16, 13*16, 5*16,
855 };
856 GLint rBits = _mesa_bitcount(rmask);
857 GLint gBits = _mesa_bitcount(gmask);
858 GLint bBits = _mesa_bitcount(bmask);
859 GLint maxBits;
860 GLuint i;
861
862 /* convert pixel components in [0,_mask] to RGB values in [0,255] */
863 for (i=0; i<=rmask; i++)
864 v->PixelToR[i] = (unsigned char) ((i * 255) / rmask);
865 for (i=0; i<=gmask; i++)
866 v->PixelToG[i] = (unsigned char) ((i * 255) / gmask);
867 for (i=0; i<=bmask; i++)
868 v->PixelToB[i] = (unsigned char) ((i * 255) / bmask);
869
870 /* convert RGB values from [0,255] to pixel components */
871
872 for (i=0;i<256;i++) {
873 GLint r = gamma_adjust(v->RedGamma, i, 255);
874 GLint g = gamma_adjust(v->GreenGamma, i, 255);
875 GLint b = gamma_adjust(v->BlueGamma, i, 255);
876 v->RtoPixel[i] = (r >> (8-rBits)) << v->rshift;
877 v->GtoPixel[i] = (g >> (8-gBits)) << v->gshift;
878 v->BtoPixel[i] = (b >> (8-bBits)) << v->bshift;
879 }
880 /* overflow protection */
881 for (i=256;i<512;i++) {
882 v->RtoPixel[i] = v->RtoPixel[255];
883 v->GtoPixel[i] = v->GtoPixel[255];
884 v->BtoPixel[i] = v->BtoPixel[255];
885 }
886
887 /* setup dithering kernel */
888 maxBits = rBits;
889 if (gBits > maxBits) maxBits = gBits;
890 if (bBits > maxBits) maxBits = bBits;
891 for (i=0;i<16;i++) {
892 v->Kernel[i] = kernel[i] >> maxBits;
893 }
894
895 v->undithered_pf = PF_Truecolor;
896 v->dithered_pf = (GET_VISUAL_DEPTH(v)<24) ? PF_Dither_True : PF_Truecolor;
897 }
898
899 /*
900 * Now check for TrueColor visuals which we can optimize.
901 */
902 if ( GET_REDMASK(v) ==0x0000ff
903 && GET_GREENMASK(v)==0x00ff00
904 && GET_BLUEMASK(v) ==0xff0000
905 && CHECK_BYTE_ORDER(v)
906 && v->BitsPerPixel==32
907 && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
908 /* common 32 bpp config used on SGI, Sun */
909 v->undithered_pf = v->dithered_pf = PF_8A8B8G8R; /* ABGR */
910 }
911 else if (GET_REDMASK(v) == 0xff0000
912 && GET_GREENMASK(v)== 0x00ff00
913 && GET_BLUEMASK(v) == 0x0000ff
914 && CHECK_BYTE_ORDER(v)
915 && v->RedGamma == 1.0 && v->GreenGamma == 1.0 && v->BlueGamma == 1.0){
916 if (v->BitsPerPixel==32) {
917 /* if 32 bpp, and visual indicates 8 bpp alpha channel */
918 if (GET_VISUAL_DEPTH(v) == 32 && v->mesa_visual.alphaBits == 8)
919 v->undithered_pf = v->dithered_pf = PF_8A8R8G8B; /* ARGB */
920 else
921 v->undithered_pf = v->dithered_pf = PF_8R8G8B; /* xRGB */
922 }
923 else if (v->BitsPerPixel == 24) {
924 v->undithered_pf = v->dithered_pf = PF_8R8G8B24; /* RGB */
925 }
926 }
927 else if (GET_REDMASK(v) ==0xf800
928 && GET_GREENMASK(v)==0x07e0
929 && GET_BLUEMASK(v) ==0x001f
930 && CHECK_BYTE_ORDER(v)
931 && v->BitsPerPixel==16
932 && v->RedGamma==1.0 && v->GreenGamma==1.0 && v->BlueGamma==1.0) {
933 /* 5-6-5 RGB */
934 v->undithered_pf = PF_5R6G5B;
935 v->dithered_pf = PF_Dither_5R6G5B;
936 }
937 }
938
939
940
941 /**
942 * Setup RGB rendering for a window with a monochrome visual.
943 */
944 static void
945 setup_monochrome( XMesaVisual v, XMesaBuffer b )
946 {
947 (void) b;
948 v->dithered_pf = v->undithered_pf = PF_1Bit;
949 /* if black=1 then we must flip pixel values */
950 v->bitFlip = (GET_BLACK_PIXEL(v) != 0);
951 }
952
953
954
955 /**
956 * When a context is bound for the first time, we can finally finish
957 * initializing the context's visual and buffer information.
958 * \param v the XMesaVisual to initialize
959 * \param b the XMesaBuffer to initialize (may be NULL)
960 * \param rgb_flag TRUE = RGBA mode, FALSE = color index mode
961 * \param window the window/pixmap we're rendering into
962 * \param cmap the colormap associated with the window/pixmap
963 * \return GL_TRUE=success, GL_FALSE=failure
964 */
965 static GLboolean
966 initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
967 GLboolean rgb_flag, XMesaDrawable window,
968 XMesaColormap cmap)
969 {
970 int client = 0;
971
972 #ifdef XFree86Server
973 client = (window) ? CLIENT_ID(window->id) : 0;
974 #endif
975
976 ASSERT(!b || b->xm_visual == v);
977
978 /* Save true bits/pixel */
979 v->BitsPerPixel = bits_per_pixel(v);
980 assert(v->BitsPerPixel > 0);
981
982 if (rgb_flag == GL_FALSE) {
983 /* COLOR-INDEXED WINDOW:
984 * Even if the visual is TrueColor or DirectColor we treat it as
985 * being color indexed. This is weird but might be useful to someone.
986 */
987 v->dithered_pf = v->undithered_pf = PF_Index;
988 v->mesa_visual.indexBits = GET_VISUAL_DEPTH(v);
989 }
990 else {
991 /* RGB WINDOW:
992 * We support RGB rendering into almost any kind of visual.
993 */
994 const int xclass = v->mesa_visual.visualType;
995 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
996 setup_truecolor( v, b, cmap );
997 }
998 else if (xclass == GLX_STATIC_GRAY && GET_VISUAL_DEPTH(v) == 1) {
999 setup_monochrome( v, b );
1000 }
1001 else if (xclass == GLX_GRAY_SCALE || xclass == GLX_STATIC_GRAY) {
1002 if (!setup_grayscale( client, v, b, cmap )) {
1003 return GL_FALSE;
1004 }
1005 }
1006 else if ((xclass == GLX_PSEUDO_COLOR || xclass == GLX_STATIC_COLOR)
1007 && GET_VISUAL_DEPTH(v)>=4 && GET_VISUAL_DEPTH(v)<=16) {
1008 if (!setup_dithered_color( client, v, b, cmap )) {
1009 return GL_FALSE;
1010 }
1011 }
1012 else {
1013 _mesa_warning(NULL, "XMesa: RGB mode rendering not supported in given visual.\n");
1014 return GL_FALSE;
1015 }
1016 v->mesa_visual.indexBits = 0;
1017
1018 if (_mesa_getenv("MESA_NO_DITHER")) {
1019 v->dithered_pf = v->undithered_pf;
1020 }
1021 }
1022
1023
1024 /*
1025 * If MESA_INFO env var is set print out some debugging info
1026 * which can help Brian figure out what's going on when a user
1027 * reports bugs.
1028 */
1029 if (_mesa_getenv("MESA_INFO")) {
1030 _mesa_printf("X/Mesa visual = %p\n", (void *) v);
1031 _mesa_printf("X/Mesa dithered pf = %u\n", v->dithered_pf);
1032 _mesa_printf("X/Mesa undithered pf = %u\n", v->undithered_pf);
1033 _mesa_printf("X/Mesa level = %d\n", v->mesa_visual.level);
1034 _mesa_printf("X/Mesa depth = %d\n", GET_VISUAL_DEPTH(v));
1035 _mesa_printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel);
1036 }
1037
1038 if (b && window) {
1039 char *data;
1040
1041 /* Do window-specific initializations */
1042
1043 /* these should have been set in create_xmesa_buffer */
1044 ASSERT(b->frontxrb->drawable == window);
1045 ASSERT(b->frontxrb->pixmap == (XMesaPixmap) window);
1046
1047 /* Setup for single/double buffering */
1048 if (v->mesa_visual.doubleBufferMode) {
1049 /* Double buffered */
1050 b->shm = check_for_xshm( v->display );
1051 }
1052
1053 /* X11 graphics contexts */
1054 #ifdef XFree86Server
1055 b->gc = CreateScratchGC(v->display, window->depth);
1056 #else
1057 b->gc = XCreateGC( v->display, window, 0, NULL );
1058 #endif
1059 XMesaSetFunction( v->display, b->gc, GXcopy );
1060
1061 /* cleargc - for glClear() */
1062 #ifdef XFree86Server
1063 b->cleargc = CreateScratchGC(v->display, window->depth);
1064 #else
1065 b->cleargc = XCreateGC( v->display, window, 0, NULL );
1066 #endif
1067 XMesaSetFunction( v->display, b->cleargc, GXcopy );
1068
1069 /*
1070 * Don't generate Graphics Expose/NoExpose events in swapbuffers().
1071 * Patch contributed by Michael Pichler May 15, 1995.
1072 */
1073 #ifdef XFree86Server
1074 b->swapgc = CreateScratchGC(v->display, window->depth);
1075 {
1076 CARD32 v[1];
1077 v[0] = FALSE;
1078 dixChangeGC(NullClient, b->swapgc, GCGraphicsExposures, v, NULL);
1079 }
1080 #else
1081 {
1082 XGCValues gcvalues;
1083 gcvalues.graphics_exposures = False;
1084 b->swapgc = XCreateGC(v->display, window,
1085 GCGraphicsExposures, &gcvalues);
1086 }
1087 #endif
1088 XMesaSetFunction( v->display, b->swapgc, GXcopy );
1089
1090 /* Initialize the row buffer XImage for use in write_color_span() */
1091 data = (char*) MALLOC(MAX_WIDTH*4);
1092 #ifdef XFree86Server
1093 b->rowimage = XMesaCreateImage(GET_VISUAL_DEPTH(v), MAX_WIDTH, 1, data);
1094 #else
1095 b->rowimage = XCreateImage( v->display,
1096 v->visinfo->visual,
1097 v->visinfo->depth,
1098 ZPixmap, 0, /*format, offset*/
1099 data, /*data*/
1100 MAX_WIDTH, 1, /*width, height*/
1101 32, /*bitmap_pad*/
1102 0 /*bytes_per_line*/ );
1103 #endif
1104 if (!b->rowimage)
1105 return GL_FALSE;
1106 }
1107
1108 return GL_TRUE;
1109 }
1110
1111
1112
1113 /*
1114 * Convert an RGBA color to a pixel value.
1115 */
1116 unsigned long
1117 xmesa_color_to_pixel(XMesaContext xmesa,
1118 GLubyte r, GLubyte g, GLubyte b, GLubyte a,
1119 GLuint pixelFormat)
1120 {
1121 GLcontext *ctx = xmesa->st->ctx;
1122
1123 switch (pixelFormat) {
1124 case PF_Index:
1125 return 0;
1126 case PF_Truecolor:
1127 {
1128 unsigned long p;
1129 PACK_TRUECOLOR( p, r, g, b );
1130 return p;
1131 }
1132 case PF_8A8B8G8R:
1133 return PACK_8A8B8G8R( r, g, b, a );
1134 case PF_8A8R8G8B:
1135 return PACK_8A8R8G8B( r, g, b, a );
1136 case PF_8R8G8B:
1137 /* fall through */
1138 case PF_8R8G8B24:
1139 return PACK_8R8G8B( r, g, b );
1140 case PF_5R6G5B:
1141 return PACK_5R6G5B( r, g, b );
1142 case PF_Dither:
1143 {
1144 DITHER_SETUP;
1145 return DITHER( 1, 0, r, g, b );
1146 }
1147 case PF_1Bit:
1148 /* 382 = (3*255)/2 */
1149 return ((r+g+b) > 382) ^ xmesa->xm_visual->bitFlip;
1150 case PF_Lookup:
1151 {
1152 LOOKUP_SETUP;
1153 return LOOKUP( r, g, b );
1154 }
1155 case PF_Grayscale:
1156 return GRAY_RGB( r, g, b );
1157 case PF_Dither_True:
1158 /* fall through */
1159 case PF_Dither_5R6G5B:
1160 {
1161 unsigned long p;
1162 PACK_TRUEDITHER(p, 1, 0, r, g, b);
1163 return p;
1164 }
1165 default:
1166 _mesa_problem(ctx, "Bad pixel format in xmesa_color_to_pixel");
1167 }
1168 return 0;
1169 }
1170
1171
1172 #define NUM_VISUAL_TYPES 6
1173
1174 /**
1175 * Convert an X visual type to a GLX visual type.
1176 *
1177 * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
1178 * to be converted.
1179 * \return If \c visualType is a valid X visual type, a GLX visual type will
1180 * be returned. Otherwise \c GLX_NONE will be returned.
1181 *
1182 * \note
1183 * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
1184 * DRI CVS tree.
1185 */
1186 static GLint
1187 xmesa_convert_from_x_visual_type( int visualType )
1188 {
1189 static const int glx_visual_types[ NUM_VISUAL_TYPES ] = {
1190 GLX_STATIC_GRAY, GLX_GRAY_SCALE,
1191 GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
1192 GLX_TRUE_COLOR, GLX_DIRECT_COLOR
1193 };
1194
1195 return ( (unsigned) visualType < NUM_VISUAL_TYPES )
1196 ? glx_visual_types[ visualType ] : GLX_NONE;
1197 }
1198
1199
1200 /**********************************************************************/
1201 /***** Public Functions *****/
1202 /**********************************************************************/
1203
1204
1205 /*
1206 * Create a new X/Mesa visual.
1207 * Input: display - X11 display
1208 * visinfo - an XVisualInfo pointer
1209 * rgb_flag - GL_TRUE = RGB mode,
1210 * GL_FALSE = color index mode
1211 * alpha_flag - alpha buffer requested?
1212 * db_flag - GL_TRUE = double-buffered,
1213 * GL_FALSE = single buffered
1214 * stereo_flag - stereo visual?
1215 * ximage_flag - GL_TRUE = use an XImage for back buffer,
1216 * GL_FALSE = use an off-screen pixmap for back buffer
1217 * depth_size - requested bits/depth values, or zero
1218 * stencil_size - requested bits/stencil values, or zero
1219 * accum_red_size - requested bits/red accum values, or zero
1220 * accum_green_size - requested bits/green accum values, or zero
1221 * accum_blue_size - requested bits/blue accum values, or zero
1222 * accum_alpha_size - requested bits/alpha accum values, or zero
1223 * num_samples - number of samples/pixel if multisampling, or zero
1224 * level - visual level, usually 0
1225 * visualCaveat - ala the GLX extension, usually GLX_NONE
1226 * Return; a new XMesaVisual or 0 if error.
1227 */
1228 PUBLIC
1229 XMesaVisual XMesaCreateVisual( XMesaDisplay *display,
1230 XMesaVisualInfo visinfo,
1231 GLboolean rgb_flag,
1232 GLboolean alpha_flag,
1233 GLboolean db_flag,
1234 GLboolean stereo_flag,
1235 GLboolean ximage_flag,
1236 GLint depth_size,
1237 GLint stencil_size,
1238 GLint accum_red_size,
1239 GLint accum_green_size,
1240 GLint accum_blue_size,
1241 GLint accum_alpha_size,
1242 GLint num_samples,
1243 GLint level,
1244 GLint visualCaveat )
1245 {
1246 char *gamma;
1247 XMesaVisual v;
1248 GLint red_bits, green_bits, blue_bits, alpha_bits;
1249
1250 #ifndef XFree86Server
1251 /* For debugging only */
1252 if (_mesa_getenv("MESA_XSYNC")) {
1253 /* This makes debugging X easier.
1254 * In your debugger, set a breakpoint on _XError to stop when an
1255 * X protocol error is generated.
1256 */
1257 XSynchronize( display, 1 );
1258 }
1259 #endif
1260
1261 v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual);
1262 if (!v) {
1263 return NULL;
1264 }
1265
1266 v->display = display;
1267
1268 /* Save a copy of the XVisualInfo struct because the user may X_mesa_free()
1269 * the struct but we may need some of the information contained in it
1270 * at a later time.
1271 */
1272 #ifndef XFree86Server
1273 v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo));
1274 if(!v->visinfo) {
1275 _mesa_free(v);
1276 return NULL;
1277 }
1278 MEMCPY(v->visinfo, visinfo, sizeof(*visinfo));
1279 #endif
1280
1281 /* check for MESA_GAMMA environment variable */
1282 gamma = _mesa_getenv("MESA_GAMMA");
1283 if (gamma) {
1284 v->RedGamma = v->GreenGamma = v->BlueGamma = 0.0;
1285 sscanf( gamma, "%f %f %f", &v->RedGamma, &v->GreenGamma, &v->BlueGamma );
1286 if (v->RedGamma<=0.0) v->RedGamma = 1.0;
1287 if (v->GreenGamma<=0.0) v->GreenGamma = v->RedGamma;
1288 if (v->BlueGamma<=0.0) v->BlueGamma = v->RedGamma;
1289 }
1290 else {
1291 v->RedGamma = v->GreenGamma = v->BlueGamma = 1.0;
1292 }
1293
1294 v->ximage_flag = ximage_flag;
1295
1296 #ifdef XFree86Server
1297 /* We could calculate these values by ourselves. nplanes is either the sum
1298 * of the red, green, and blue bits or the number index bits.
1299 * ColormapEntries is either (1U << index_bits) or
1300 * (1U << max(redBits, greenBits, blueBits)).
1301 */
1302 assert(visinfo->nplanes > 0);
1303 v->nplanes = visinfo->nplanes;
1304 v->ColormapEntries = visinfo->ColormapEntries;
1305
1306 v->mesa_visual.redMask = visinfo->redMask;
1307 v->mesa_visual.greenMask = visinfo->greenMask;
1308 v->mesa_visual.blueMask = visinfo->blueMask;
1309 v->mesa_visual.visualID = visinfo->vid;
1310 v->mesa_visual.screen = 0; /* FIXME: What should be done here? */
1311 #else
1312 v->mesa_visual.redMask = visinfo->red_mask;
1313 v->mesa_visual.greenMask = visinfo->green_mask;
1314 v->mesa_visual.blueMask = visinfo->blue_mask;
1315 v->mesa_visual.visualID = visinfo->visualid;
1316 v->mesa_visual.screen = visinfo->screen;
1317 #endif
1318
1319 #if defined(XFree86Server) || !(defined(__cplusplus) || defined(c_plusplus))
1320 v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class);
1321 #else
1322 v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
1323 #endif
1324
1325 v->mesa_visual.visualRating = visualCaveat;
1326
1327 if (alpha_flag)
1328 v->mesa_visual.alphaBits = 8;
1329
1330 (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 );
1331
1332 {
1333 const int xclass = v->mesa_visual.visualType;
1334 if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
1335 red_bits = _mesa_bitcount(GET_REDMASK(v));
1336 green_bits = _mesa_bitcount(GET_GREENMASK(v));
1337 blue_bits = _mesa_bitcount(GET_BLUEMASK(v));
1338 }
1339 else {
1340 /* this is an approximation */
1341 int depth;
1342 depth = GET_VISUAL_DEPTH(v);
1343 red_bits = depth / 3;
1344 depth -= red_bits;
1345 green_bits = depth / 2;
1346 depth -= green_bits;
1347 blue_bits = depth;
1348 alpha_bits = 0;
1349 assert( red_bits + green_bits + blue_bits == GET_VISUAL_DEPTH(v) );
1350 }
1351 alpha_bits = v->mesa_visual.alphaBits;
1352 }
1353
1354 _mesa_initialize_visual( &v->mesa_visual,
1355 rgb_flag, db_flag, stereo_flag,
1356 red_bits, green_bits,
1357 blue_bits, alpha_bits,
1358 v->mesa_visual.indexBits,
1359 depth_size,
1360 stencil_size,
1361 accum_red_size, accum_green_size,
1362 accum_blue_size, accum_alpha_size,
1363 0 );
1364
1365 /* XXX minor hack */
1366 v->mesa_visual.level = level;
1367 return v;
1368 }
1369
1370
1371 PUBLIC
1372 void XMesaDestroyVisual( XMesaVisual v )
1373 {
1374 #ifndef XFree86Server
1375 _mesa_free(v->visinfo);
1376 #endif
1377 _mesa_free(v);
1378 }
1379
1380
1381
1382 static void
1383 finish_or_flush( GLcontext *ctx )
1384 {
1385 #ifdef XFree86Server
1386 /* NOT_NEEDED */
1387 #else
1388 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
1389 ctx->st->pipe->flush(ctx->st->pipe, 0);
1390 if (xmesa) {
1391 _glthread_LOCK_MUTEX(_xmesa_lock);
1392 XSync( xmesa->display, False );
1393 _glthread_UNLOCK_MUTEX(_xmesa_lock);
1394 }
1395 #endif
1396 }
1397
1398
1399 /**
1400 * Called by glViewport.
1401 * This is a good time for us to poll the current X window size and adjust
1402 * our renderbuffers to match the current window size.
1403 * Remember, we have no opportunity to respond to conventional
1404 * X Resize/StructureNotify events since the X driver has no event loop.
1405 * Thus, we poll.
1406 * Note that this trick isn't fool-proof. If the application never calls
1407 * glViewport, our notion of the current window size may be incorrect.
1408 * That problem led to the GLX_MESA_resize_buffers extension.
1409 */
1410 static void
1411 xmesa_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
1412 {
1413 XMesaContext xmctx = XMESA_CONTEXT(ctx);
1414 XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer);
1415 XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer);
1416 xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf);
1417 xmesa_check_and_update_buffer_size(xmctx, xmreadbuf);
1418 (void) x;
1419 (void) y;
1420 (void) w;
1421 (void) h;
1422 }
1423
1424
1425 /**
1426 * Initialize the device driver function table with the functions
1427 * we implement in this driver.
1428 */
1429 static void
1430 xmesa_init_driver_functions(struct dd_function_table *driver)
1431 {
1432 #if 0 /* not needed for now */
1433 driver->Flush = finish_or_flush;
1434 driver->Finish = finish_or_flush;
1435 #else
1436 (void) finish_or_flush;
1437 #endif
1438 driver->Viewport = xmesa_viewport;
1439 }
1440
1441
1442 /**
1443 * Create a new XMesaContext.
1444 * \param v the XMesaVisual
1445 * \param share_list another XMesaContext with which to share display
1446 * lists or NULL if no sharing is wanted.
1447 * \return an XMesaContext or NULL if error.
1448 */
1449 PUBLIC
1450 XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
1451 {
1452 static GLboolean firstTime = GL_TRUE;
1453 struct pipe_context *pipe;
1454 XMesaContext c;
1455 GLcontext *mesaCtx;
1456
1457 if (firstTime) {
1458 _glthread_INIT_MUTEX(_xmesa_lock);
1459 firstTime = GL_FALSE;
1460 }
1461
1462 /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */
1463 c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
1464 if (!c)
1465 return NULL;
1466
1467 pipe = xmesa_create_softpipe( c );
1468
1469 c->st = st_create_context(pipe, &v->mesa_visual,
1470 share_list ? share_list->st : NULL);
1471 mesaCtx = c->st->ctx;
1472 c->st->ctx->DriverCtx = c;
1473
1474 #if 00
1475 _mesa_enable_sw_extensions(mesaCtx);
1476 _mesa_enable_1_3_extensions(mesaCtx);
1477 _mesa_enable_1_4_extensions(mesaCtx);
1478 _mesa_enable_1_5_extensions(mesaCtx);
1479 _mesa_enable_2_0_extensions(mesaCtx);
1480 #endif
1481
1482 #ifdef XFree86Server
1483 /* If we're running in the X server, do bounds checking to prevent
1484 * segfaults and server crashes!
1485 */
1486 mesaCtx->Const.CheckArrayBounds = GL_TRUE;
1487 #endif
1488
1489 xmesa_init_driver_functions(&mesaCtx->Driver);
1490
1491 /* finish up xmesa context initializations */
1492 c->swapbytes = CHECK_BYTE_ORDER(v) ? GL_FALSE : GL_TRUE;
1493 c->xm_visual = v;
1494 c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */
1495 c->display = v->display;
1496 c->pixelformat = v->dithered_pf; /* Dithering is enabled by default */
1497
1498 /* override these functions, as if the xlib driver were derived from
1499 * the softpipe driver.
1500 */
1501 pipe->get_tile = xmesa_get_tile;
1502 pipe->put_tile = xmesa_put_tile;
1503 pipe->get_tile_rgba = xmesa_get_tile_rgba;
1504 pipe->put_tile_rgba = xmesa_put_tile_rgba;
1505
1506 c->st->haveFramebufferRegions = GL_FALSE;
1507
1508 /* special pipe->clear function */
1509 pipe->clear = xmesa_clear;
1510
1511 return c;
1512 }
1513
1514
1515
1516 PUBLIC
1517 void XMesaDestroyContext( XMesaContext c )
1518 {
1519 st_destroy_context(c->st);
1520 _mesa_free(c);
1521 }
1522
1523
1524
1525 /**
1526 * Private function for creating an XMesaBuffer which corresponds to an
1527 * X window or pixmap.
1528 * \param v the window's XMesaVisual
1529 * \param w the window we're wrapping
1530 * \return new XMesaBuffer or NULL if error
1531 */
1532 PUBLIC XMesaBuffer
1533 XMesaCreateWindowBuffer(XMesaVisual v, XMesaWindow w)
1534 {
1535 #ifndef XFree86Server
1536 XWindowAttributes attr;
1537 #endif
1538 XMesaBuffer b;
1539 XMesaColormap cmap;
1540 int depth;
1541
1542 assert(v);
1543 assert(w);
1544
1545 /* Check that window depth matches visual depth */
1546 #ifdef XFree86Server
1547 depth = ((XMesaDrawable)w)->depth;
1548 #else
1549 XGetWindowAttributes( v->display, w, &attr );
1550 depth = attr.depth;
1551 #endif
1552 if (GET_VISUAL_DEPTH(v) != depth) {
1553 _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
1554 GET_VISUAL_DEPTH(v), depth);
1555 return NULL;
1556 }
1557
1558 /* Find colormap */
1559 #ifdef XFree86Server
1560 cmap = (ColormapPtr)LookupIDByType(wColormap(w), RT_COLORMAP);
1561 #else
1562 if (attr.colormap) {
1563 cmap = attr.colormap;
1564 }
1565 else {
1566 _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w);
1567 /* this is weird, a window w/out a colormap!? */
1568 /* OK, let's just allocate a new one and hope for the best */
1569 cmap = XCreateColormap(v->display, w, attr.visual, AllocNone);
1570 }
1571 #endif
1572
1573 b = create_xmesa_buffer((XMesaDrawable) w, WINDOW, v, cmap);
1574 if (!b)
1575 return NULL;
1576
1577 if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode,
1578 (XMesaDrawable) w, cmap )) {
1579 xmesa_free_buffer(b);
1580 return NULL;
1581 }
1582
1583 return b;
1584 }
1585
1586
1587
1588 /**
1589 * Create a new XMesaBuffer from an X pixmap.
1590 *
1591 * \param v the XMesaVisual
1592 * \param p the pixmap
1593 * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or
1594 * \c GLX_DIRECT_COLOR visual for the pixmap
1595 * \returns new XMesaBuffer or NULL if error
1596 */
1597 PUBLIC XMesaBuffer
1598 XMesaCreatePixmapBuffer(XMesaVisual v, XMesaPixmap p, XMesaColormap cmap)
1599 {
1600 XMesaBuffer b;
1601
1602 assert(v);
1603
1604 b = create_xmesa_buffer((XMesaDrawable) p, PIXMAP, v, cmap);
1605 if (!b)
1606 return NULL;
1607
1608 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1609 (XMesaDrawable) p, cmap)) {
1610 xmesa_free_buffer(b);
1611 return NULL;
1612 }
1613
1614 return b;
1615 }
1616
1617
1618 /**
1619 * For GLX_EXT_texture_from_pixmap
1620 */
1621 XMesaBuffer
1622 XMesaCreatePixmapTextureBuffer(XMesaVisual v, XMesaPixmap p,
1623 XMesaColormap cmap,
1624 int format, int target, int mipmap)
1625 {
1626 GET_CURRENT_CONTEXT(ctx);
1627 XMesaBuffer b;
1628 GLuint width, height;
1629
1630 assert(v);
1631
1632 b = create_xmesa_buffer((XMesaDrawable) p, PIXMAP, v, cmap);
1633 if (!b)
1634 return NULL;
1635
1636 /* get pixmap size, update framebuffer/renderbuffer dims */
1637 xmesa_get_window_size(v->display, b, &width, &height);
1638 _mesa_resize_framebuffer(NULL, &(b->stfb->Base), width, height);
1639
1640 if (target == 0) {
1641 /* examine dims */
1642 if (ctx->Extensions.ARB_texture_non_power_of_two) {
1643 target = GLX_TEXTURE_2D_EXT;
1644 }
1645 else if ( _mesa_bitcount(width) == 1
1646 && _mesa_bitcount(height) == 1) {
1647 /* power of two size */
1648 if (height == 1) {
1649 target = GLX_TEXTURE_1D_EXT;
1650 }
1651 else {
1652 target = GLX_TEXTURE_2D_EXT;
1653 }
1654 }
1655 else if (ctx->Extensions.NV_texture_rectangle) {
1656 target = GLX_TEXTURE_RECTANGLE_EXT;
1657 }
1658 else {
1659 /* non power of two textures not supported */
1660 XMesaDestroyBuffer(b);
1661 return 0;
1662 }
1663 }
1664
1665 b->TextureTarget = target;
1666 b->TextureFormat = format;
1667 b->TextureMipmap = mipmap;
1668
1669 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1670 (XMesaDrawable) p, cmap)) {
1671 xmesa_free_buffer(b);
1672 return NULL;
1673 }
1674
1675 return b;
1676 }
1677
1678
1679
1680 XMesaBuffer
1681 XMesaCreatePBuffer(XMesaVisual v, XMesaColormap cmap,
1682 unsigned int width, unsigned int height)
1683 {
1684 #ifndef XFree86Server
1685 XMesaWindow root;
1686 XMesaDrawable drawable; /* X Pixmap Drawable */
1687 XMesaBuffer b;
1688
1689 /* allocate pixmap for front buffer */
1690 root = RootWindow( v->display, v->visinfo->screen );
1691 drawable = XCreatePixmap(v->display, root, width, height,
1692 v->visinfo->depth);
1693 if (!drawable)
1694 return NULL;
1695
1696 b = create_xmesa_buffer(drawable, PBUFFER, v, cmap);
1697 if (!b)
1698 return NULL;
1699
1700 if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
1701 drawable, cmap)) {
1702 xmesa_free_buffer(b);
1703 return NULL;
1704 }
1705
1706 return b;
1707 #else
1708 return 0;
1709 #endif
1710 }
1711
1712
1713
1714 /*
1715 * Deallocate an XMesaBuffer structure and all related info.
1716 */
1717 PUBLIC void
1718 XMesaDestroyBuffer(XMesaBuffer b)
1719 {
1720 xmesa_free_buffer(b);
1721 }
1722
1723
1724 /**
1725 * Query the current window size and update the corresponding GLframebuffer
1726 * and all attached renderbuffers.
1727 * Called when:
1728 * 1. the first time a buffer is bound to a context.
1729 * 2. from glViewport to poll for window size changes
1730 * 3. from the XMesaResizeBuffers() API function.
1731 * Note: it's possible (and legal) for xmctx to be NULL. That can happen
1732 * when resizing a buffer when no rendering context is bound.
1733 */
1734 void
1735 xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer)
1736 {
1737 GLuint width, height;
1738 xmesa_get_window_size(drawBuffer->display, drawBuffer, &width, &height);
1739 st_resize_framebuffer(drawBuffer->stfb, width, height);
1740 }
1741
1742
1743 /*
1744 * Bind buffer b to context c and make c the current rendering context.
1745 */
1746 GLboolean XMesaMakeCurrent( XMesaContext c, XMesaBuffer b )
1747 {
1748 return XMesaMakeCurrent2( c, b, b );
1749 }
1750
1751
1752 /*
1753 * Bind buffer b to context c and make c the current rendering context.
1754 */
1755 PUBLIC
1756 GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
1757 XMesaBuffer readBuffer )
1758 {
1759 if (c) {
1760 if (!drawBuffer || !readBuffer)
1761 return GL_FALSE; /* must specify buffers! */
1762
1763 #if 0
1764 /* XXX restore this optimization */
1765 if (&(c->mesa) == _mesa_get_current_context()
1766 && c->mesa.DrawBuffer == &drawBuffer->mesa_buffer
1767 && c->mesa.ReadBuffer == &readBuffer->mesa_buffer
1768 && XMESA_BUFFER(c->mesa.DrawBuffer)->wasCurrent) {
1769 /* same context and buffer, do nothing */
1770 return GL_TRUE;
1771 }
1772 #endif
1773
1774 c->xm_buffer = drawBuffer;
1775
1776 /* Call this periodically to detect when the user has begun using
1777 * GL rendering from multiple threads.
1778 */
1779 _glapi_check_multithread();
1780
1781 xmesa_check_and_update_buffer_size(c, drawBuffer);
1782 if (readBuffer != drawBuffer)
1783 xmesa_check_and_update_buffer_size(c, readBuffer);
1784
1785 st_make_current(c->st, drawBuffer->stfb, readBuffer->stfb);
1786
1787 #if 0
1788 if (c->xm_visual->mesa_visual.rgbMode) {
1789 /*
1790 * Must recompute and set these pixel values because colormap
1791 * can be different for different windows.
1792 */
1793 c->clearpixel = xmesa_color_to_pixel( c,
1794 c->clearcolor[0],
1795 c->clearcolor[1],
1796 c->clearcolor[2],
1797 c->clearcolor[3],
1798 c->xm_visual->undithered_pf);
1799 XMesaSetForeground(c->display, drawBuffer->cleargc, c->clearpixel);
1800 }
1801 #endif
1802
1803 /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
1804 drawBuffer->wasCurrent = GL_TRUE;
1805 }
1806 else {
1807 /* Detach */
1808 st_make_current( NULL, NULL, NULL );
1809 }
1810 return GL_TRUE;
1811 }
1812
1813
1814 /*
1815 * Unbind the context c from its buffer.
1816 */
1817 GLboolean XMesaUnbindContext( XMesaContext c )
1818 {
1819 /* A no-op for XFree86 integration purposes */
1820 return GL_TRUE;
1821 }
1822
1823
1824 XMesaContext XMesaGetCurrentContext( void )
1825 {
1826 GET_CURRENT_CONTEXT(ctx);
1827 if (ctx) {
1828 XMesaContext xmesa = XMESA_CONTEXT(ctx);
1829 return xmesa;
1830 }
1831 else {
1832 return 0;
1833 }
1834 }
1835
1836
1837 XMesaBuffer XMesaGetCurrentBuffer( void )
1838 {
1839 GET_CURRENT_CONTEXT(ctx);
1840 if (ctx) {
1841 XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer);
1842 return xmbuf;
1843 }
1844 else {
1845 return 0;
1846 }
1847 }
1848
1849
1850 /* New in Mesa 3.1 */
1851 XMesaBuffer XMesaGetCurrentReadBuffer( void )
1852 {
1853 GET_CURRENT_CONTEXT(ctx);
1854 if (ctx) {
1855 return XMESA_BUFFER(ctx->ReadBuffer);
1856 }
1857 else {
1858 return 0;
1859 }
1860 }
1861
1862
1863 #ifdef XFree86Server
1864 PUBLIC
1865 GLboolean XMesaForceCurrent(XMesaContext c)
1866 {
1867 if (c) {
1868 _glapi_set_dispatch(c->mesa.CurrentDispatch);
1869
1870 if (&(c->mesa) != _mesa_get_current_context()) {
1871 _mesa_make_current(&c->mesa, c->mesa.DrawBuffer, c->mesa.ReadBuffer);
1872 }
1873 }
1874 else {
1875 _mesa_make_current(NULL, NULL, NULL);
1876 }
1877 return GL_TRUE;
1878 }
1879
1880
1881 PUBLIC
1882 GLboolean XMesaLoseCurrent(XMesaContext c)
1883 {
1884 (void) c;
1885 _mesa_make_current(NULL, NULL, NULL);
1886 return GL_TRUE;
1887 }
1888
1889
1890 PUBLIC
1891 GLboolean XMesaCopyContext( XMesaContext xm_src, XMesaContext xm_dst, GLuint mask )
1892 {
1893 _mesa_copy_context(&xm_src->mesa, &xm_dst->mesa, mask);
1894 return GL_TRUE;
1895 }
1896 #endif /* XFree86Server */
1897
1898
1899 #ifndef FX
1900 GLboolean XMesaSetFXmode( GLint mode )
1901 {
1902 (void) mode;
1903 return GL_FALSE;
1904 }
1905 #endif
1906
1907
1908
1909 /*
1910 * Copy the back buffer to the front buffer. If there's no back buffer
1911 * this is a no-op.
1912 */
1913 PUBLIC
1914 void XMesaSwapBuffers( XMesaBuffer b )
1915 {
1916 if (!b->backxrb) {
1917 /* single buffered */
1918 return;
1919 }
1920
1921 /* If we're swapping the buffer associated with the current context
1922 * we have to flush any pending rendering commands first.
1923 */
1924 st_notify_swapbuffers(b->stfb);
1925
1926 if (b->db_mode) {
1927 if (b->backxrb->ximage) {
1928 /* Copy Ximage (back buf) from client memory to server window */
1929 #if defined(USE_XSHM) && !defined(XFree86Server)
1930 if (b->shm) {
1931 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
1932 XShmPutImage( b->xm_visual->display, b->frontxrb->drawable,
1933 b->swapgc,
1934 b->backxrb->ximage, 0, 0,
1935 0, 0, xmesa_buffer_width(b), xmesa_buffer_height(b),
1936 False );
1937 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
1938 }
1939 else
1940 #endif
1941 {
1942 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
1943 XMesaPutImage( b->xm_visual->display, b->frontxrb->drawable,
1944 b->swapgc,
1945 b->backxrb->ximage, 0, 0,
1946 0, 0,
1947 xmesa_buffer_width(b), xmesa_buffer_height(b));
1948 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
1949 }
1950 }
1951 else if (b->backxrb->pixmap) {
1952 /* Copy pixmap (back buf) to window (front buf) on server */
1953 /*_glthread_LOCK_MUTEX(_xmesa_lock);*/
1954 XMesaCopyArea( b->xm_visual->display,
1955 b->backxrb->pixmap, /* source drawable */
1956 b->frontxrb->drawable, /* dest. drawable */
1957 b->swapgc,
1958 0, 0, xmesa_buffer_width(b), xmesa_buffer_height(b),
1959 0, 0 /* dest region */
1960 );
1961 /*_glthread_UNLOCK_MUTEX(_xmesa_lock);*/
1962 }
1963
1964 if (b->swAlpha) {
1965 GET_CURRENT_CONTEXT(ctx);
1966 _mesa_copy_soft_alpha_renderbuffers(ctx, &b->stfb->Base);
1967 }
1968 }
1969 #if !defined(XFree86Server)
1970 XSync( b->xm_visual->display, False );
1971 #endif
1972 }
1973
1974
1975
1976 /*
1977 * Copy sub-region of back buffer to front buffer
1978 */
1979 void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
1980 {
1981 if (!b->backxrb) {
1982 /* single buffered */
1983 return;
1984 }
1985
1986 /* If we're swapping the buffer associated with the current context
1987 * we have to flush any pending rendering commands first.
1988 */
1989 st_notify_swapbuffers(b->stfb);
1990
1991 if (b->db_mode) {
1992 int yTop = xmesa_buffer_height(b) - y - height;
1993 if (b->backxrb->ximage) {
1994 /* Copy Ximage from host's memory to server's window */
1995 #if defined(USE_XSHM) && !defined(XFree86Server)
1996 if (b->shm) {
1997 /* XXX assuming width and height aren't too large! */
1998 XShmPutImage( b->xm_visual->display, b->frontxrb->drawable,
1999 b->swapgc,
2000 b->backxrb->ximage, x, yTop,
2001 x, yTop, width, height, False );
2002 /* wait for finished event??? */
2003 }
2004 else
2005 #endif
2006 {
2007 /* XXX assuming width and height aren't too large! */
2008 XMesaPutImage( b->xm_visual->display, b->frontxrb->drawable,
2009 b->swapgc,
2010 b->backxrb->ximage, x, yTop,
2011 x, yTop, width, height );
2012 }
2013 }
2014 else {
2015 /* Copy pixmap to window on server */
2016 XMesaCopyArea( b->xm_visual->display,
2017 b->backxrb->pixmap, /* source drawable */
2018 b->frontxrb->drawable, /* dest. drawable */
2019 b->swapgc,
2020 x, yTop, width, height, /* source region */
2021 x, yTop /* dest region */
2022 );
2023 }
2024 }
2025 }
2026
2027
2028 /*
2029 * Return a pointer to the XMesa backbuffer Pixmap or XImage. This function
2030 * is a way to get "under the hood" of X/Mesa so one can manipulate the
2031 * back buffer directly.
2032 * Output: pixmap - pointer to back buffer's Pixmap, or 0
2033 * ximage - pointer to back buffer's XImage, or NULL
2034 * Return: GL_TRUE = context is double buffered
2035 * GL_FALSE = context is single buffered
2036 */
2037 #ifndef XFree86Server
2038 GLboolean XMesaGetBackBuffer( XMesaBuffer b,
2039 XMesaPixmap *pixmap,
2040 XMesaImage **ximage )
2041 {
2042 if (b->db_mode) {
2043 if (pixmap)
2044 *pixmap = b->backxrb->pixmap;
2045 if (ximage)
2046 *ximage = b->backxrb->ximage;
2047 return GL_TRUE;
2048 }
2049 else {
2050 *pixmap = 0;
2051 *ximage = NULL;
2052 return GL_FALSE;
2053 }
2054 }
2055 #endif /* XFree86Server */
2056
2057
2058 /*
2059 * Return the depth buffer associated with an XMesaBuffer.
2060 * Input: b - the XMesa buffer handle
2061 * Output: width, height - size of buffer in pixels
2062 * bytesPerValue - bytes per depth value (2 or 4)
2063 * buffer - pointer to depth buffer values
2064 * Return: GL_TRUE or GL_FALSE to indicate success or failure.
2065 */
2066 GLboolean XMesaGetDepthBuffer( XMesaBuffer b, GLint *width, GLint *height,
2067 GLint *bytesPerValue, void **buffer )
2068 {
2069 struct gl_renderbuffer *rb
2070 = b->stfb->Base.Attachment[BUFFER_DEPTH].Renderbuffer;
2071 if (!rb || !rb->Data) {
2072 *width = 0;
2073 *height = 0;
2074 *bytesPerValue = 0;
2075 *buffer = 0;
2076 return GL_FALSE;
2077 }
2078 else {
2079 *width = xmesa_buffer_width(b);
2080 *height = xmesa_buffer_height(b);
2081 *bytesPerValue = b->stfb->Base.Visual.depthBits <= 16
2082 ? sizeof(GLushort) : sizeof(GLuint);
2083 *buffer = rb->Data;
2084 return GL_TRUE;
2085 }
2086 }
2087
2088
2089 void XMesaFlush( XMesaContext c )
2090 {
2091 if (c && c->display) {
2092 #ifdef XFree86Server
2093 /* NOT_NEEDED */
2094 #else
2095 XSync( c->display, False );
2096 #endif
2097 }
2098 }
2099
2100
2101
2102 const char *XMesaGetString( XMesaContext c, int name )
2103 {
2104 (void) c;
2105 if (name==XMESA_VERSION) {
2106 return "5.0";
2107 }
2108 else if (name==XMESA_EXTENSIONS) {
2109 return "";
2110 }
2111 else {
2112 return NULL;
2113 }
2114 }
2115
2116
2117
2118 XMesaBuffer XMesaFindBuffer( XMesaDisplay *dpy, XMesaDrawable d )
2119 {
2120 XMesaBuffer b;
2121 for (b=XMesaBufferList; b; b=b->Next) {
2122 if (b->frontxrb->drawable == d && b->display == dpy) {
2123 return b;
2124 }
2125 }
2126 return NULL;
2127 }
2128
2129
2130 /**
2131 * Free/destroy all XMesaBuffers associated with given display.
2132 */
2133 void xmesa_destroy_buffers_on_display(XMesaDisplay *dpy)
2134 {
2135 XMesaBuffer b, next;
2136 for (b = XMesaBufferList; b; b = next) {
2137 next = b->Next;
2138 if (b->display == dpy) {
2139 xmesa_free_buffer(b);
2140 }
2141 }
2142 }
2143
2144
2145 /*
2146 * Look for XMesaBuffers whose X window has been destroyed.
2147 * Deallocate any such XMesaBuffers.
2148 */
2149 void XMesaGarbageCollect( void )
2150 {
2151 XMesaBuffer b, next;
2152 for (b=XMesaBufferList; b; b=next) {
2153 next = b->Next;
2154 if (b->display && b->frontxrb->drawable && b->type == WINDOW) {
2155 #ifdef XFree86Server
2156 /* NOT_NEEDED */
2157 #else
2158 XSync(b->display, False);
2159 if (!window_exists( b->display, b->frontxrb->drawable )) {
2160 /* found a dead window, free the ancillary info */
2161 XMesaDestroyBuffer( b );
2162 }
2163 #endif
2164 }
2165 }
2166 }
2167
2168
2169 unsigned long XMesaDitherColor( XMesaContext xmesa, GLint x, GLint y,
2170 GLfloat red, GLfloat green,
2171 GLfloat blue, GLfloat alpha )
2172 {
2173 GLcontext *ctx = xmesa->st->ctx;
2174 GLint r = (GLint) (red * 255.0F);
2175 GLint g = (GLint) (green * 255.0F);
2176 GLint b = (GLint) (blue * 255.0F);
2177 GLint a = (GLint) (alpha * 255.0F);
2178
2179 switch (xmesa->pixelformat) {
2180 case PF_Index:
2181 return 0;
2182 case PF_Truecolor:
2183 {
2184 unsigned long p;
2185 PACK_TRUECOLOR( p, r, g, b );
2186 return p;
2187 }
2188 case PF_8A8B8G8R:
2189 return PACK_8A8B8G8R( r, g, b, a );
2190 case PF_8A8R8G8B:
2191 return PACK_8A8R8G8B( r, g, b, a );
2192 case PF_8R8G8B:
2193 return PACK_8R8G8B( r, g, b );
2194 case PF_5R6G5B:
2195 return PACK_5R6G5B( r, g, b );
2196 case PF_Dither:
2197 {
2198 DITHER_SETUP;
2199 return DITHER( x, y, r, g, b );
2200 }
2201 case PF_1Bit:
2202 /* 382 = (3*255)/2 */
2203 return ((r+g+b) > 382) ^ xmesa->xm_visual->bitFlip;
2204 case PF_Lookup:
2205 {
2206 LOOKUP_SETUP;
2207 return LOOKUP( r, g, b );
2208 }
2209 case PF_Grayscale:
2210 return GRAY_RGB( r, g, b );
2211 case PF_Dither_5R6G5B:
2212 /* fall through */
2213 case PF_Dither_True:
2214 {
2215 unsigned long p;
2216 PACK_TRUEDITHER(p, x, y, r, g, b);
2217 return p;
2218 }
2219 default:
2220 _mesa_problem(NULL, "Bad pixel format in XMesaDitherColor");
2221 }
2222 return 0;
2223 }
2224
2225
2226 /*
2227 * This is typically called when the window size changes and we need
2228 * to reallocate the buffer's back/depth/stencil/accum buffers.
2229 */
2230 PUBLIC void
2231 XMesaResizeBuffers( XMesaBuffer b )
2232 {
2233 GET_CURRENT_CONTEXT(ctx);
2234 XMesaContext xmctx = XMESA_CONTEXT(ctx);
2235 if (!xmctx)
2236 return;
2237 xmesa_check_and_update_buffer_size(xmctx, b);
2238 }
2239
2240
2241 static GLint
2242 xbuffer_to_renderbuffer(int buffer)
2243 {
2244 assert(MAX_AUX_BUFFERS <= 4);
2245
2246 switch (buffer) {
2247 case GLX_FRONT_LEFT_EXT:
2248 return BUFFER_FRONT_LEFT;
2249 case GLX_FRONT_RIGHT_EXT:
2250 return BUFFER_FRONT_RIGHT;
2251 case GLX_BACK_LEFT_EXT:
2252 return BUFFER_BACK_LEFT;
2253 case GLX_BACK_RIGHT_EXT:
2254 return BUFFER_BACK_RIGHT;
2255 case GLX_AUX0_EXT:
2256 return BUFFER_AUX0;
2257 case GLX_AUX1_EXT:
2258 return BUFFER_AUX1;
2259 case GLX_AUX2_EXT:
2260 return BUFFER_AUX2;
2261 case GLX_AUX3_EXT:
2262 return BUFFER_AUX3;
2263 case GLX_AUX4_EXT:
2264 case GLX_AUX5_EXT:
2265 case GLX_AUX6_EXT:
2266 case GLX_AUX7_EXT:
2267 case GLX_AUX8_EXT:
2268 case GLX_AUX9_EXT:
2269 default:
2270 /* BadValue error */
2271 return -1;
2272 }
2273 }
2274
2275
2276 PUBLIC void
2277 XMesaBindTexImage(XMesaDisplay *dpy, XMesaBuffer drawable, int buffer,
2278 const int *attrib_list)
2279 {
2280 #if 0
2281 GET_CURRENT_CONTEXT(ctx);
2282 const GLuint unit = ctx->Texture.CurrentUnit;
2283 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
2284 struct gl_texture_object *texObj;
2285 #endif
2286 struct gl_renderbuffer *rb;
2287 struct xmesa_renderbuffer *xrb;
2288 GLint b;
2289 XMesaImage *img = NULL;
2290 GLboolean freeImg = GL_FALSE;
2291
2292 b = xbuffer_to_renderbuffer(buffer);
2293 if (b < 0)
2294 return;
2295
2296 if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_NONE_EXT)
2297 return; /* BadMatch error */
2298
2299 rb = drawable->stfb->Base.Attachment[b].Renderbuffer;
2300 if (!rb) {
2301 /* invalid buffer */
2302 return;
2303 }
2304 xrb = xmesa_renderbuffer(rb);
2305
2306 #if 0
2307 switch (drawable->TextureTarget) {
2308 case GLX_TEXTURE_1D_EXT:
2309 texObj = texUnit->Current1D;
2310 break;
2311 case GLX_TEXTURE_2D_EXT:
2312 texObj = texUnit->Current2D;
2313 break;
2314 case GLX_TEXTURE_RECTANGLE_EXT:
2315 texObj = texUnit->CurrentRect;
2316 break;
2317 default:
2318 return; /* BadMatch error */
2319 }
2320 #endif
2321
2322 /*
2323 * The following is a quick and simple way to implement
2324 * BindTexImage. The better way is to write some new FetchTexel()
2325 * functions which would extract texels from XImages. We'd still
2326 * need to use GetImage when texturing from a Pixmap (front buffer)
2327 * but texturing from a back buffer (XImage) would avoid an image
2328 * copy.
2329 */
2330
2331 /* get XImage */
2332 if (xrb->pixmap) {
2333 img = XMesaGetImage(dpy, xrb->pixmap, 0, 0, rb->Width, rb->Height, ~0L,
2334 ZPixmap);
2335 freeImg = GL_TRUE;
2336 }
2337 else if (xrb->ximage) {
2338 img = xrb->ximage;
2339 }
2340
2341 /* store the XImage as a new texture image */
2342 if (img) {
2343 GLenum format, type, intFormat;
2344 if (img->bits_per_pixel == 32) {
2345 format = GL_BGRA;
2346 type = GL_UNSIGNED_BYTE;
2347 intFormat = GL_RGBA;
2348 }
2349 else if (img->bits_per_pixel == 24) {
2350 format = GL_BGR;
2351 type = GL_UNSIGNED_BYTE;
2352 intFormat = GL_RGB;
2353 }
2354 else if (img->bits_per_pixel == 16) {
2355 format = GL_BGR;
2356 type = GL_UNSIGNED_SHORT_5_6_5;
2357 intFormat = GL_RGB;
2358 }
2359 else {
2360 _mesa_problem(NULL, "Unexpected XImage format in XMesaBindTexImage");
2361 return;
2362 }
2363 if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_RGBA_EXT) {
2364 intFormat = GL_RGBA;
2365 }
2366 else if (drawable->TextureFormat == GLX_TEXTURE_FORMAT_RGB_EXT) {
2367 intFormat = GL_RGB;
2368 }
2369
2370 _mesa_TexImage2D(GL_TEXTURE_2D, 0, intFormat, rb->Width, rb->Height, 0,
2371 format, type, img->data);
2372
2373 if (freeImg) {
2374 XMesaDestroyImage(img);
2375 }
2376 }
2377 }
2378
2379
2380
2381 PUBLIC void
2382 XMesaReleaseTexImage(XMesaDisplay *dpy, XMesaBuffer drawable, int buffer)
2383 {
2384 const GLint b = xbuffer_to_renderbuffer(buffer);
2385 if (b < 0)
2386 return;
2387
2388 /* no-op for now */
2389 }
2390