/* * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "glitz_glxint.h" #include #include static int _glitz_glx_format_compare (const void *elem1, const void *elem2) { glitz_int_drawable_format_t *format[2]; int i, score[2]; format[0] = (glitz_int_drawable_format_t *) elem1; format[1] = (glitz_int_drawable_format_t *) elem2; i = score[0] = score[1] = 0; for (; i < 2; i++) { if (format[i]->d.color.fourcc != GLITZ_FOURCC_RGB) score[i] -= 1000; if (format[i]->d.color.red_size) { if (format[i]->d.color.red_size >= 8) score[i] += 5; score[i] += 10; } if (format[i]->d.color.alpha_size) { if (format[i]->d.color.alpha_size >= 8) score[i] += 5; score[i] += 10; } if (format[i]->d.stencil_size) score[i] += 5; if (format[i]->d.depth_size) score[i] += 5; if (format[i]->d.doublebuffer) score[i] += 10; if (format[i]->d.samples > 1) score[i] -= (20 - format[i]->d.samples); if (format[i]->types & GLITZ_DRAWABLE_TYPE_WINDOW_MASK) score[i] += 10; if (format[i]->types & GLITZ_DRAWABLE_TYPE_PBUFFER_MASK) score[i] += 10; if (format[i]->caveat) score[i] -= 1000; } return score[1] - score[0]; } static void _glitz_add_format (glitz_glx_screen_info_t *screen_info, glitz_int_drawable_format_t *format) { int n = screen_info->n_formats; screen_info->formats = realloc (screen_info->formats, sizeof (glitz_int_drawable_format_t) * (n + 1)); if (screen_info->formats) { screen_info->formats[n] = *format; screen_info->formats[n].d.id = n; screen_info->n_formats++; } } static void _glitz_glx_query_formats (glitz_glx_screen_info_t *screen_info) { Display *display; glitz_int_drawable_format_t format; XVisualInfo visual_templ; XVisualInfo *visuals; int i, num_visuals; display = screen_info->display_info->display; visual_templ.screen = screen_info->screen; visuals = XGetVisualInfo (display, VisualScreenMask, &visual_templ, &num_visuals); /* No pbuffers without fbconfigs */ format.types = GLITZ_DRAWABLE_TYPE_WINDOW_MASK; format.d.id = 0; format.d.color.fourcc = GLITZ_FOURCC_RGB; for (i = 0; i < num_visuals; i++) { int value; if ((glXGetConfig (display, &visuals[i], GLX_USE_GL, &value) != 0) || (value == 0)) continue; glXGetConfig (display, &visuals[i], GLX_RGBA, &value); if (value == 0) continue; /* Stereo is not supported yet */ glXGetConfig (display, &visuals[i], GLX_STEREO, &value); if (value != 0) continue; glXGetConfig (display, &visuals[i], GLX_RED_SIZE, &value); format.d.color.red_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_GREEN_SIZE, &value); format.d.color.green_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_BLUE_SIZE, &value); format.d.color.blue_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_ALPHA_SIZE, &value); format.d.color.alpha_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_DEPTH_SIZE, &value); format.d.depth_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_STENCIL_SIZE, &value); format.d.stencil_size = (unsigned short) value; glXGetConfig (display, &visuals[i], GLX_DOUBLEBUFFER, &value); format.d.doublebuffer = (value) ? 1: 0; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_VISUAL_RATING_MASK) { glXGetConfig (display, &visuals[i], GLX_VISUAL_CAVEAT_EXT, &value); switch (value) { case GLX_SLOW_VISUAL_EXT: case GLX_NON_CONFORMANT_VISUAL_EXT: format.caveat = 1; break; default: format.caveat = 0; break; } } else format.caveat = 0; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_MULTISAMPLE_MASK) { glXGetConfig (display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &value); if (value) { glXGetConfig (display, &visuals[i], GLX_SAMPLES_ARB, &value); format.d.samples = (unsigned short) (value > 1)? value: 1; } else format.d.samples = 1; } else format.d.samples = 1; format.u.uval = visuals[i].visualid; _glitz_add_format (screen_info, &format); } if (visuals) XFree (visuals); } static glitz_status_t _glitz_glx_query_formats_using_fbconfigs (glitz_glx_screen_info_t *screen_info) { glitz_glx_static_proc_address_list_t *glx = &screen_info->glx; Display *display; glitz_int_drawable_format_t format; GLXFBConfig *fbconfigs; int i, num_configs; display = screen_info->display_info->display; fbconfigs = glx->get_fbconfigs (display, screen_info->screen, &num_configs); if (!fbconfigs) { /* fbconfigs are not supported, falling back to visuals */ screen_info->glx_feature_mask &= ~GLITZ_GLX_FEATURE_FBCONFIG_MASK; screen_info->glx_feature_mask &= ~GLITZ_GLX_FEATURE_PBUFFER_MASK; return GLITZ_STATUS_NOT_SUPPORTED; } for (i = 0; i < num_configs; i++) { int value; if ((glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_RENDER_TYPE, &value) != 0) || (!(value & GLX_RGBA_BIT))) continue; /* Stereo is not supported yet */ glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_STEREO, &value); if (value != 0) continue; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_DRAWABLE_TYPE, &value); if (!((value & GLX_WINDOW_BIT) || (value & GLX_PBUFFER_BIT))) continue; format.types = 0; if (value & GLX_WINDOW_BIT) format.types |= GLITZ_DRAWABLE_TYPE_WINDOW_MASK; if (value & GLX_PBUFFER_BIT) format.types |= GLITZ_DRAWABLE_TYPE_PBUFFER_MASK; format.d.id = 0; format.d.color.fourcc = GLITZ_FOURCC_RGB; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_FBCONFIG_ID, &value); format.u.uval = value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_RED_SIZE, &value); format.d.color.red_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_GREEN_SIZE, &value); format.d.color.green_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_BLUE_SIZE, &value); format.d.color.blue_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_ALPHA_SIZE, &value); format.d.color.alpha_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_DEPTH_SIZE, &value); format.d.depth_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_STENCIL_SIZE, &value); format.d.stencil_size = (unsigned short) value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_DOUBLEBUFFER, &value); format.d.doublebuffer = (value)? 1: 0; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_CONFIG_CAVEAT, &value); switch (value) { case GLX_SLOW_VISUAL_EXT: case GLX_NON_CONFORMANT_VISUAL_EXT: format.caveat = 1; break; default: format.caveat = 0; break; } if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_MULTISAMPLE_MASK) { glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_SAMPLE_BUFFERS_ARB, &value); if (value) { glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_SAMPLES_ARB, &value); format.d.samples = (unsigned short) (value > 1)? value: 1; if (format.d.samples > 1) { if (!(screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_PBUFFER_MULTISAMPLE_MASK)) format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK; } } else format.d.samples = 1; } else format.d.samples = 1; _glitz_add_format (screen_info, &format); } if (fbconfigs) XFree (fbconfigs); return GLITZ_STATUS_SUCCESS; } void glitz_glx_query_formats (glitz_glx_screen_info_t *screen_info) { glitz_status_t status = GLITZ_STATUS_NOT_SUPPORTED; int i; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_FBCONFIG_MASK) status = _glitz_glx_query_formats_using_fbconfigs (screen_info); if (status) _glitz_glx_query_formats (screen_info); if (!screen_info->n_formats) return; qsort (screen_info->formats, screen_info->n_formats, sizeof (glitz_int_drawable_format_t), _glitz_glx_format_compare); for (i = 0; i < screen_info->n_formats; i++) screen_info->formats[i].d.id = i; } glitz_drawable_format_t * glitz_glx_find_window_format (Display *display, int screen, unsigned long mask, const glitz_drawable_format_t *templ, int count) { glitz_int_drawable_format_t itempl; glitz_glx_screen_info_t *screen_info = glitz_glx_screen_info_get (display, screen); glitz_drawable_format_copy (templ, &itempl.d, mask); itempl.types = GLITZ_DRAWABLE_TYPE_WINDOW_MASK; mask |= GLITZ_INT_FORMAT_WINDOW_MASK; return glitz_drawable_format_find (screen_info->formats, screen_info->n_formats, mask, &itempl, count); } slim_hidden_def(glitz_glx_find_window_format); glitz_drawable_format_t * glitz_glx_find_pbuffer_format (Display *display, int screen, unsigned long mask, const glitz_drawable_format_t *templ, int count) { glitz_int_drawable_format_t itempl; glitz_glx_screen_info_t *screen_info = glitz_glx_screen_info_get (display, screen); glitz_drawable_format_copy (templ, &itempl.d, mask); itempl.types = GLITZ_DRAWABLE_TYPE_PBUFFER_MASK; mask |= GLITZ_INT_FORMAT_PBUFFER_MASK; return glitz_drawable_format_find (screen_info->formats, screen_info->n_formats, mask, &itempl, count); } slim_hidden_def(glitz_glx_find_pbuffer_format); glitz_drawable_format_t * glitz_glx_find_drawable_format_for_visual (Display *display, int screen, VisualID visual_id) { glitz_drawable_format_t *format = NULL; glitz_glx_screen_info_t *screen_info; int i; screen_info = glitz_glx_screen_info_get (display, screen); if (!screen_info) return NULL; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_FBCONFIG_MASK) { glitz_glx_static_proc_address_list_t *glx = &screen_info->glx; GLXFBConfig *fbconfigs; int fid, n_fbconfigs; fid = -1; fbconfigs = glx->get_fbconfigs (display, screen, &n_fbconfigs); for (i = 0; i < n_fbconfigs; i++) { XVisualInfo *visinfo; visinfo = glx->get_visual_from_fbconfig (display, fbconfigs[i]); if (visinfo && visinfo->visualid == visual_id) { int value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_FBCONFIG_ID, &value); for (fid = 0; fid < screen_info->n_formats; fid++) { if (screen_info->formats[fid].u.uval == value) { format = &screen_info->formats[fid].d; break; } } if (format) break; } } if (fbconfigs) XFree (fbconfigs); } else { for (i = 0; i < screen_info->n_formats; i++) { if (visual_id == screen_info->formats[i].u.uval) { format = &screen_info->formats[i].d; break; } } } return format; } slim_hidden_def(glitz_glx_find_drawable_format_for_visual); XVisualInfo * glitz_glx_get_visual_info_from_format (Display *display, int screen, glitz_drawable_format_t *format) { XVisualInfo *vinfo = NULL; glitz_glx_screen_info_t *screen_info = glitz_glx_screen_info_get (display, screen); glitz_glx_static_proc_address_list_t *glx = &screen_info->glx; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_FBCONFIG_MASK) { GLXFBConfig *fbconfigs; int i, n_fbconfigs; int fbconfigid = screen_info->formats[format->id].u.uval; fbconfigs = glx->get_fbconfigs (display, screen, &n_fbconfigs); for (i = 0; i < n_fbconfigs; i++) { int value; glx->get_fbconfig_attrib (display, fbconfigs[i], GLX_FBCONFIG_ID, &value); if (value == fbconfigid) break; } if (i < n_fbconfigs) vinfo = glx->get_visual_from_fbconfig (display, fbconfigs[i]); if (fbconfigs) XFree (fbconfigs); } else { XVisualInfo templ; int n_items; templ.visualid = screen_info->formats[format->id].u.uval; vinfo = XGetVisualInfo (display, VisualIDMask, &templ, &n_items); } return vinfo; } slim_hidden_def(glitz_glx_get_visual_info_from_format);