glxextensions.c revision af69d88d
1cdc920a0Smrg/* 2cdc920a0Smrg * (C) Copyright IBM Corporation 2002, 2004 3cdc920a0Smrg * All Rights Reserved. 4cdc920a0Smrg * 5cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a 6cdc920a0Smrg * copy of this software and associated documentation files (the "Software"), 7cdc920a0Smrg * to deal in the Software without restriction, including without limitation 8cdc920a0Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 9cdc920a0Smrg * license, and/or sell copies of the Software, and to permit persons to whom 10cdc920a0Smrg * the Software is furnished to do so, subject to the following conditions: 11cdc920a0Smrg * 12cdc920a0Smrg * The above copyright notice and this permission notice (including the next 13cdc920a0Smrg * paragraph) shall be included in all copies or substantial portions of the 14cdc920a0Smrg * Software. 15cdc920a0Smrg * 16cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17cdc920a0Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18cdc920a0Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19cdc920a0Smrg * THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20cdc920a0Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21cdc920a0Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22cdc920a0Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 23cdc920a0Smrg */ 24cdc920a0Smrg 25cdc920a0Smrg/** 26cdc920a0Smrg * \file glxextensions.c 27cdc920a0Smrg * 28cdc920a0Smrg * \author Ian Romanick <idr@us.ibm.com> 29cdc920a0Smrg */ 30cdc920a0Smrg 31cdc920a0Smrg#include "glxclient.h" 32cdc920a0Smrg#include <X11/extensions/extutil.h> 33cdc920a0Smrg#include <X11/extensions/Xext.h> 34cdc920a0Smrg#include <string.h> 35cdc920a0Smrg#include "glxextensions.h" 36cdc920a0Smrg 37cdc920a0Smrg 38cdc920a0Smrg#define SET_BIT(m,b) (m[ (b) / 8 ] |= (1U << ((b) % 8))) 39cdc920a0Smrg#define CLR_BIT(m,b) (m[ (b) / 8 ] &= ~(1U << ((b) % 8))) 40cdc920a0Smrg#define IS_SET(m,b) ((m[ (b) / 8 ] & (1U << ((b) % 8))) != 0) 41cdc920a0Smrg#define CONCAT(a,b) a ## b 42cdc920a0Smrg#define GLX(n) "GLX_" # n, 4 + sizeof( # n ) - 1, CONCAT(n,_bit) 43cdc920a0Smrg#define GL(n) "GL_" # n, 3 + sizeof( # n ) - 1, GL_ ## n ## _bit 44cdc920a0Smrg#define VER(a,b) a, b 45cdc920a0Smrg#define Y 1 46cdc920a0Smrg#define N 0 47cdc920a0Smrg#define EXT_ENABLED(bit,supported) (IS_SET( supported, bit )) 48cdc920a0Smrg 49cdc920a0Smrg 50cdc920a0Smrgstruct extension_info 51cdc920a0Smrg{ 52cdc920a0Smrg const char *const name; 53cdc920a0Smrg unsigned name_len; 54cdc920a0Smrg 55cdc920a0Smrg unsigned char bit; 56cdc920a0Smrg 57cdc920a0Smrg /* This is the lowest version of GLX that "requires" this extension. 58cdc920a0Smrg * For example, GLX 1.3 requires SGIX_fbconfig, SGIX_pbuffer, and 59cdc920a0Smrg * SGI_make_current_read. If the extension is not required by any known 60cdc920a0Smrg * version of GLX, use 0, 0. 61cdc920a0Smrg */ 62cdc920a0Smrg unsigned char version_major; 63cdc920a0Smrg unsigned char version_minor; 64cdc920a0Smrg unsigned char client_support; 65cdc920a0Smrg unsigned char direct_support; 66cdc920a0Smrg unsigned char client_only; /** Is the extension client-side only? */ 67cdc920a0Smrg unsigned char direct_only; /** Is the extension for direct 68cdc920a0Smrg * contexts only? 69cdc920a0Smrg */ 70cdc920a0Smrg}; 71cdc920a0Smrg 72cdc920a0Smrg/* *INDENT-OFF* */ 73cdc920a0Smrgstatic const struct extension_info known_glx_extensions[] = { 74af69d88dSmrg { GLX(ARB_create_context), VER(0,0), Y, N, N, N }, 75af69d88dSmrg { GLX(ARB_create_context_profile), VER(0,0), Y, N, N, N }, 76af69d88dSmrg { GLX(ARB_create_context_robustness), VER(0,0), Y, N, N, N }, 77af69d88dSmrg { GLX(ARB_fbconfig_float), VER(0,0), Y, Y, N, N }, 78af69d88dSmrg { GLX(ARB_framebuffer_sRGB), VER(0,0), Y, Y, N, N }, 79cdc920a0Smrg { GLX(ARB_get_proc_address), VER(1,4), Y, N, Y, N }, 80cdc920a0Smrg { GLX(ARB_multisample), VER(1,4), Y, Y, N, N }, 81cdc920a0Smrg { GLX(ATI_pixel_format_float), VER(0,0), N, N, N, N }, 82cdc920a0Smrg { GLX(EXT_import_context), VER(0,0), Y, Y, N, N }, 83cdc920a0Smrg { GLX(EXT_visual_info), VER(0,0), Y, Y, N, N }, 84cdc920a0Smrg { GLX(EXT_visual_rating), VER(0,0), Y, Y, N, N }, 85af69d88dSmrg { GLX(EXT_fbconfig_packed_float), VER(0,0), Y, Y, N, N }, 863464ebd5Sriastradh { GLX(EXT_framebuffer_sRGB), VER(0,0), Y, Y, N, N }, 87af69d88dSmrg { GLX(EXT_create_context_es2_profile), VER(0,0), Y, N, N, Y }, 88cdc920a0Smrg { GLX(MESA_copy_sub_buffer), VER(0,0), Y, N, N, N }, 893464ebd5Sriastradh { GLX(MESA_multithread_makecurrent),VER(0,0), Y, N, Y, N }, 90af69d88dSmrg { GLX(MESA_query_renderer), VER(0,0), Y, N, N, Y }, 91cdc920a0Smrg { GLX(MESA_swap_control), VER(0,0), Y, N, N, Y }, 92cdc920a0Smrg { GLX(NV_float_buffer), VER(0,0), N, N, N, N }, 93cdc920a0Smrg { GLX(OML_swap_method), VER(0,0), Y, Y, N, N }, 94cdc920a0Smrg { GLX(OML_sync_control), VER(0,0), Y, N, N, Y }, 95cdc920a0Smrg { GLX(SGI_make_current_read), VER(1,3), Y, N, N, N }, 96cdc920a0Smrg { GLX(SGI_swap_control), VER(0,0), Y, N, N, N }, 97cdc920a0Smrg { GLX(SGI_video_sync), VER(0,0), Y, N, N, Y }, 98cdc920a0Smrg { GLX(SGIS_multisample), VER(0,0), Y, Y, N, N }, 99cdc920a0Smrg { GLX(SGIX_fbconfig), VER(1,3), Y, Y, N, N }, 100cdc920a0Smrg { GLX(SGIX_pbuffer), VER(1,3), Y, Y, N, N }, 101cdc920a0Smrg { GLX(SGIX_swap_barrier), VER(0,0), N, N, N, N }, 102cdc920a0Smrg { GLX(SGIX_swap_group), VER(0,0), N, N, N, N }, 103cdc920a0Smrg { GLX(SGIX_visual_select_group), VER(0,0), Y, Y, N, N }, 104cdc920a0Smrg { GLX(EXT_texture_from_pixmap), VER(0,0), Y, N, N, N }, 105af69d88dSmrg { GLX(INTEL_swap_event), VER(0,0), Y, N, N, N }, 106af69d88dSmrg { GLX(EXT_buffer_age), VER(0,0), Y, N, N, Y }, 107cdc920a0Smrg { NULL } 108cdc920a0Smrg}; 109cdc920a0Smrg 110cdc920a0Smrgstatic const struct extension_info known_gl_extensions[] = { 111cdc920a0Smrg { GL(ARB_depth_texture), VER(1,4), Y, N, N, N }, 112cdc920a0Smrg { GL(ARB_draw_buffers), VER(0,0), Y, N, N, N }, 113cdc920a0Smrg { GL(ARB_fragment_program), VER(0,0), Y, N, N, N }, 114cdc920a0Smrg { GL(ARB_fragment_program_shadow), VER(0,0), Y, N, N, N }, 115cdc920a0Smrg { GL(ARB_framebuffer_object), VER(0,0), Y, N, N, N }, 116cdc920a0Smrg { GL(ARB_imaging), VER(0,0), Y, N, N, N }, 117cdc920a0Smrg { GL(ARB_multisample), VER(1,3), Y, N, N, N }, 118cdc920a0Smrg { GL(ARB_multitexture), VER(1,3), Y, N, N, N }, 119cdc920a0Smrg { GL(ARB_occlusion_query), VER(1,5), Y, N, N, N }, 120cdc920a0Smrg { GL(ARB_point_parameters), VER(1,4), Y, N, N, N }, 121cdc920a0Smrg { GL(ARB_point_sprite), VER(0,0), Y, N, N, N }, 122cdc920a0Smrg { GL(ARB_shadow), VER(1,4), Y, N, N, N }, 123cdc920a0Smrg { GL(ARB_shadow_ambient), VER(0,0), Y, N, N, N }, 124cdc920a0Smrg { GL(ARB_texture_border_clamp), VER(1,3), Y, N, N, N }, 125cdc920a0Smrg { GL(ARB_texture_compression), VER(1,3), Y, N, N, N }, 126cdc920a0Smrg { GL(ARB_texture_cube_map), VER(1,3), Y, N, N, N }, 127cdc920a0Smrg { GL(ARB_texture_env_add), VER(1,3), Y, N, N, N }, 128cdc920a0Smrg { GL(ARB_texture_env_combine), VER(1,3), Y, N, N, N }, 129cdc920a0Smrg { GL(ARB_texture_env_crossbar), VER(1,4), Y, N, N, N }, 130cdc920a0Smrg { GL(ARB_texture_env_dot3), VER(1,3), Y, N, N, N }, 131cdc920a0Smrg { GL(ARB_texture_mirrored_repeat), VER(1,4), Y, N, N, N }, 132cdc920a0Smrg { GL(ARB_texture_non_power_of_two), VER(1,5), Y, N, N, N }, 133cdc920a0Smrg { GL(ARB_texture_rectangle), VER(0,0), Y, N, N, N }, 1343464ebd5Sriastradh { GL(ARB_texture_rg), VER(0,0), Y, N, N, N }, 135cdc920a0Smrg { GL(ARB_transpose_matrix), VER(1,3), Y, N, Y, N }, 136cdc920a0Smrg { GL(ARB_vertex_buffer_object), VER(1,5), N, N, N, N }, 137cdc920a0Smrg { GL(ARB_vertex_program), VER(0,0), Y, N, N, N }, 138cdc920a0Smrg { GL(ARB_window_pos), VER(1,4), Y, N, N, N }, 139cdc920a0Smrg { GL(EXT_abgr), VER(0,0), Y, N, N, N }, 140cdc920a0Smrg { GL(EXT_bgra), VER(1,2), Y, N, N, N }, 141cdc920a0Smrg { GL(EXT_blend_color), VER(1,4), Y, N, N, N }, 142cdc920a0Smrg { GL(EXT_blend_equation_separate), VER(0,0), Y, N, N, N }, 143cdc920a0Smrg { GL(EXT_blend_func_separate), VER(1,4), Y, N, N, N }, 144cdc920a0Smrg { GL(EXT_blend_logic_op), VER(1,4), Y, N, N, N }, 145cdc920a0Smrg { GL(EXT_blend_minmax), VER(1,4), Y, N, N, N }, 146cdc920a0Smrg { GL(EXT_blend_subtract), VER(1,4), Y, N, N, N }, 147cdc920a0Smrg { GL(EXT_clip_volume_hint), VER(0,0), Y, N, N, N }, 148cdc920a0Smrg { GL(EXT_compiled_vertex_array), VER(0,0), N, N, N, N }, 149cdc920a0Smrg { GL(EXT_convolution), VER(0,0), N, N, N, N }, 150cdc920a0Smrg { GL(EXT_copy_texture), VER(1,1), Y, N, N, N }, 151cdc920a0Smrg { GL(EXT_cull_vertex), VER(0,0), N, N, N, N }, 152cdc920a0Smrg { GL(EXT_depth_bounds_test), VER(0,0), N, N, N, N }, 153cdc920a0Smrg { GL(EXT_draw_range_elements), VER(1,2), Y, N, Y, N }, 154cdc920a0Smrg { GL(EXT_fog_coord), VER(1,4), Y, N, N, N }, 155cdc920a0Smrg { GL(EXT_framebuffer_blit), VER(0,0), Y, N, N, N }, 156cdc920a0Smrg { GL(EXT_framebuffer_multisample), VER(0,0), Y, N, N, N }, 157cdc920a0Smrg { GL(EXT_framebuffer_object), VER(0,0), Y, N, N, N }, 1583464ebd5Sriastradh { GL(EXT_framebuffer_sRGB), VER(0,0), Y, N, N, N }, 159cdc920a0Smrg { GL(EXT_multi_draw_arrays), VER(1,4), Y, N, Y, N }, 160cdc920a0Smrg { GL(EXT_packed_depth_stencil), VER(0,0), Y, N, N, N }, 161cdc920a0Smrg { GL(EXT_packed_pixels), VER(1,2), Y, N, N, N }, 162cdc920a0Smrg { GL(EXT_paletted_texture), VER(0,0), Y, N, N, N }, 163cdc920a0Smrg { GL(EXT_pixel_buffer_object), VER(0,0), N, N, N, N }, 164cdc920a0Smrg { GL(EXT_point_parameters), VER(1,4), Y, N, N, N }, 165cdc920a0Smrg { GL(EXT_polygon_offset), VER(1,1), Y, N, N, N }, 166cdc920a0Smrg { GL(EXT_rescale_normal), VER(1,2), Y, N, N, N }, 167cdc920a0Smrg { GL(EXT_secondary_color), VER(1,4), Y, N, N, N }, 168cdc920a0Smrg { GL(EXT_separate_specular_color), VER(1,2), Y, N, N, N }, 169cdc920a0Smrg { GL(EXT_shadow_funcs), VER(1,5), Y, N, N, N }, 170cdc920a0Smrg { GL(EXT_shared_texture_palette), VER(0,0), Y, N, N, N }, 171cdc920a0Smrg { GL(EXT_stencil_two_side), VER(0,0), Y, N, N, N }, 172cdc920a0Smrg { GL(EXT_stencil_wrap), VER(1,4), Y, N, N, N }, 173cdc920a0Smrg { GL(EXT_subtexture), VER(1,1), Y, N, N, N }, 174cdc920a0Smrg { GL(EXT_texture), VER(1,1), Y, N, N, N }, 175cdc920a0Smrg { GL(EXT_texture3D), VER(1,2), Y, N, N, N }, 176cdc920a0Smrg { GL(EXT_texture_compression_dxt1), VER(0,0), Y, N, N, N }, 177cdc920a0Smrg { GL(EXT_texture_compression_s3tc), VER(0,0), Y, N, N, N }, 178cdc920a0Smrg { GL(EXT_texture_edge_clamp), VER(1,2), Y, N, N, N }, 179cdc920a0Smrg { GL(EXT_texture_env_add), VER(1,3), Y, N, N, N }, 180cdc920a0Smrg { GL(EXT_texture_env_combine), VER(1,3), Y, N, N, N }, 181cdc920a0Smrg { GL(EXT_texture_env_dot3), VER(0,0), Y, N, N, N }, 182cdc920a0Smrg { GL(EXT_texture_filter_anisotropic), VER(0,0), Y, N, N, N }, 183cdc920a0Smrg { GL(EXT_texture_lod), VER(1,2), Y, N, N, N }, 184cdc920a0Smrg { GL(EXT_texture_lod_bias), VER(1,4), Y, N, N, N }, 185cdc920a0Smrg { GL(EXT_texture_mirror_clamp), VER(0,0), Y, N, N, N }, 186cdc920a0Smrg { GL(EXT_texture_object), VER(1,1), Y, N, N, N }, 187cdc920a0Smrg { GL(EXT_texture_rectangle), VER(0,0), Y, N, N, N }, 188cdc920a0Smrg { GL(EXT_vertex_array), VER(0,0), Y, N, N, N }, 189cdc920a0Smrg { GL(3DFX_texture_compression_FXT1), VER(0,0), Y, N, N, N }, 190cdc920a0Smrg { GL(APPLE_packed_pixels), VER(1,2), Y, N, N, N }, 191cdc920a0Smrg { GL(APPLE_ycbcr_422), VER(0,0), Y, N, N, N }, 192cdc920a0Smrg { GL(ATI_draw_buffers), VER(0,0), Y, N, N, N }, 193cdc920a0Smrg { GL(ATI_text_fragment_shader), VER(0,0), Y, N, N, N }, 194cdc920a0Smrg { GL(ATI_texture_env_combine3), VER(0,0), Y, N, N, N }, 195cdc920a0Smrg { GL(ATI_texture_float), VER(0,0), Y, N, N, N }, 196cdc920a0Smrg { GL(ATI_texture_mirror_once), VER(0,0), Y, N, N, N }, 197cdc920a0Smrg { GL(ATIX_texture_env_combine3), VER(0,0), Y, N, N, N }, 198cdc920a0Smrg { GL(HP_convolution_border_modes), VER(0,0), Y, N, N, N }, 199cdc920a0Smrg { GL(HP_occlusion_test), VER(0,0), Y, N, N, N }, 200cdc920a0Smrg { GL(IBM_cull_vertex), VER(0,0), Y, N, N, N }, 201cdc920a0Smrg { GL(IBM_pixel_filter_hint), VER(0,0), Y, N, N, N }, 202cdc920a0Smrg { GL(IBM_rasterpos_clip), VER(0,0), Y, N, N, N }, 203cdc920a0Smrg { GL(IBM_texture_clamp_nodraw), VER(0,0), Y, N, N, N }, 204cdc920a0Smrg { GL(IBM_texture_mirrored_repeat), VER(0,0), Y, N, N, N }, 205cdc920a0Smrg { GL(INGR_blend_func_separate), VER(0,0), Y, N, N, N }, 206cdc920a0Smrg { GL(INGR_interlace_read), VER(0,0), Y, N, N, N }, 207cdc920a0Smrg { GL(MESA_pack_invert), VER(0,0), Y, N, N, N }, 208cdc920a0Smrg { GL(MESA_ycbcr_texture), VER(0,0), Y, N, N, N }, 209cdc920a0Smrg { GL(NV_blend_square), VER(1,4), Y, N, N, N }, 210cdc920a0Smrg { GL(NV_copy_depth_to_color), VER(0,0), Y, N, N, N }, 211cdc920a0Smrg { GL(NV_depth_clamp), VER(0,0), Y, N, N, N }, 212cdc920a0Smrg { GL(NV_fog_distance), VER(0,0), Y, N, N, N }, 213cdc920a0Smrg { GL(NV_fragment_program), VER(0,0), Y, N, N, N }, 214cdc920a0Smrg { GL(NV_fragment_program_option), VER(0,0), Y, N, N, N }, 215cdc920a0Smrg { GL(NV_fragment_program2), VER(0,0), Y, N, N, N }, 216cdc920a0Smrg { GL(NV_light_max_exponent), VER(0,0), Y, N, N, N }, 217cdc920a0Smrg { GL(NV_multisample_filter_hint), VER(0,0), Y, N, N, N }, 218cdc920a0Smrg { GL(NV_packed_depth_stencil), VER(0,0), Y, N, N, N }, 219cdc920a0Smrg { GL(NV_point_sprite), VER(0,0), Y, N, N, N }, 220cdc920a0Smrg { GL(NV_texgen_reflection), VER(0,0), Y, N, N, N }, 221cdc920a0Smrg { GL(NV_texture_compression_vtc), VER(0,0), Y, N, N, N }, 222cdc920a0Smrg { GL(NV_texture_env_combine4), VER(0,0), Y, N, N, N }, 223cdc920a0Smrg { GL(NV_texture_rectangle), VER(0,0), Y, N, N, N }, 224cdc920a0Smrg { GL(NV_vertex_program), VER(0,0), Y, N, N, N }, 225cdc920a0Smrg { GL(NV_vertex_program1_1), VER(0,0), Y, N, N, N }, 226cdc920a0Smrg { GL(NV_vertex_program2), VER(0,0), Y, N, N, N }, 227cdc920a0Smrg { GL(NV_vertex_program2_option), VER(0,0), Y, N, N, N }, 228cdc920a0Smrg { GL(NV_vertex_program3), VER(0,0), Y, N, N, N }, 229cdc920a0Smrg { GL(OES_read_format), VER(0,0), Y, N, N, N }, 230cdc920a0Smrg { GL(OES_compressed_paletted_texture),VER(0,0), Y, N, N, N }, 231cdc920a0Smrg { GL(SGI_color_matrix), VER(0,0), Y, N, N, N }, 232cdc920a0Smrg { GL(SGI_color_table), VER(0,0), Y, N, N, N }, 233cdc920a0Smrg { GL(SGI_texture_color_table), VER(0,0), Y, N, N, N }, 234cdc920a0Smrg { GL(SGIS_generate_mipmap), VER(1,4), Y, N, N, N }, 235cdc920a0Smrg { GL(SGIS_multisample), VER(0,0), Y, N, N, N }, 236cdc920a0Smrg { GL(SGIS_texture_border_clamp), VER(1,3), Y, N, N, N }, 237cdc920a0Smrg { GL(SGIS_texture_edge_clamp), VER(1,2), Y, N, N, N }, 238cdc920a0Smrg { GL(SGIS_texture_lod), VER(1,2), Y, N, N, N }, 239cdc920a0Smrg { GL(SGIX_blend_alpha_minmax), VER(0,0), Y, N, N, N }, 240cdc920a0Smrg { GL(SGIX_clipmap), VER(0,0), Y, N, N, N }, 241cdc920a0Smrg { GL(SGIX_depth_texture), VER(0,0), Y, N, N, N }, 242cdc920a0Smrg { GL(SGIX_fog_offset), VER(0,0), Y, N, N, N }, 243cdc920a0Smrg { GL(SGIX_shadow), VER(0,0), Y, N, N, N }, 244cdc920a0Smrg { GL(SGIX_shadow_ambient), VER(0,0), Y, N, N, N }, 245cdc920a0Smrg { GL(SGIX_texture_coordinate_clamp), VER(0,0), Y, N, N, N }, 246cdc920a0Smrg { GL(SGIX_texture_lod_bias), VER(0,0), Y, N, N, N }, 247cdc920a0Smrg { GL(SGIX_texture_range), VER(0,0), Y, N, N, N }, 248cdc920a0Smrg { GL(SGIX_texture_scale_bias), VER(0,0), Y, N, N, N }, 249cdc920a0Smrg { GL(SGIX_vertex_preclip), VER(0,0), Y, N, N, N }, 250cdc920a0Smrg { GL(SGIX_vertex_preclip_hint), VER(0,0), Y, N, N, N }, 251cdc920a0Smrg { GL(SGIX_ycrcb), VER(0,0), Y, N, N, N }, 252cdc920a0Smrg { GL(SUN_convolution_border_modes), VER(0,0), Y, N, N, N }, 253cdc920a0Smrg { GL(SUN_multi_draw_arrays), VER(0,0), Y, N, Y, N }, 254cdc920a0Smrg { GL(SUN_slice_accum), VER(0,0), Y, N, N, N }, 255cdc920a0Smrg { NULL } 256cdc920a0Smrg}; 257cdc920a0Smrg/* *INDENT-ON* */ 258cdc920a0Smrg 259cdc920a0Smrg 260cdc920a0Smrg/* global bit-fields of available extensions and their characteristics */ 261cdc920a0Smrgstatic unsigned char client_glx_support[8]; 262cdc920a0Smrgstatic unsigned char client_glx_only[8]; 263cdc920a0Smrgstatic unsigned char direct_glx_only[8]; 264cdc920a0Smrgstatic unsigned char client_gl_support[__GL_EXT_BYTES]; 265cdc920a0Smrgstatic unsigned char client_gl_only[__GL_EXT_BYTES]; 266cdc920a0Smrg 267cdc920a0Smrg/** 268cdc920a0Smrg * Bits representing the set of extensions that are enabled by default in all 269cdc920a0Smrg * direct rendering drivers. 270cdc920a0Smrg */ 271cdc920a0Smrgstatic unsigned char direct_glx_support[8]; 272cdc920a0Smrg 273cdc920a0Smrg/** 274cdc920a0Smrg * Highest core GL version that can be supported for indirect rendering. 275cdc920a0Smrg */ 276cdc920a0Smrgstatic const unsigned gl_major = 1; 277cdc920a0Smrgstatic const unsigned gl_minor = 4; 278cdc920a0Smrg 279cdc920a0Smrg/* client extensions string */ 280cdc920a0Smrgstatic const char *__glXGLXClientExtensions = NULL; 281cdc920a0Smrg 282cdc920a0Smrgstatic void __glXExtensionsCtr(void); 2833464ebd5Sriastradhstatic void __glXExtensionsCtrScreen(struct glx_screen * psc); 284cdc920a0Smrgstatic void __glXProcessServerString(const struct extension_info *ext, 285cdc920a0Smrg const char *server_string, 286cdc920a0Smrg unsigned char *server_support); 287cdc920a0Smrg 288cdc920a0Smrg/** 289cdc920a0Smrg * Set the state of a GLX extension. 290cdc920a0Smrg * 291cdc920a0Smrg * \param name Name of the extension. 292cdc920a0Smrg * \param name_len Length, in characters, of the extension name. 293cdc920a0Smrg * \param state New state (either enabled or disabled) of the extension. 294cdc920a0Smrg * \param supported Table in which the state of the extension is to be set. 295cdc920a0Smrg */ 296cdc920a0Smrgstatic void 297cdc920a0Smrgset_glx_extension(const struct extension_info *ext, 298cdc920a0Smrg const char *name, unsigned name_len, GLboolean state, 299cdc920a0Smrg unsigned char *supported) 300cdc920a0Smrg{ 301cdc920a0Smrg unsigned i; 302cdc920a0Smrg 303cdc920a0Smrg 304cdc920a0Smrg for (i = 0; ext[i].name != NULL; i++) { 305cdc920a0Smrg if ((name_len == ext[i].name_len) 306cdc920a0Smrg && (strncmp(ext[i].name, name, name_len) == 0)) { 307cdc920a0Smrg if (state) { 308cdc920a0Smrg SET_BIT(supported, ext[i].bit); 309cdc920a0Smrg } 310cdc920a0Smrg else { 311cdc920a0Smrg CLR_BIT(supported, ext[i].bit); 312cdc920a0Smrg } 313cdc920a0Smrg 314cdc920a0Smrg return; 315cdc920a0Smrg } 316cdc920a0Smrg } 317cdc920a0Smrg} 318cdc920a0Smrg 319cdc920a0Smrg 320cdc920a0Smrg#define NUL '\0' 321cdc920a0Smrg#define SEPARATOR ' ' 322cdc920a0Smrg 323cdc920a0Smrg/** 324cdc920a0Smrg * Convert the server's extension string to a bit-field. 325cdc920a0Smrg * 326cdc920a0Smrg * \param server_string GLX extension string from the server. 327cdc920a0Smrg * \param server_support Bit-field of supported extensions. 328cdc920a0Smrg * 329cdc920a0Smrg * \note 330cdc920a0Smrg * This function is used to process both GLX and GL extension strings. The 331cdc920a0Smrg * bit-fields used to track each of these have different sizes. Therefore, 332cdc920a0Smrg * the data pointed by \c server_support must be preinitialized to zero. 333cdc920a0Smrg */ 334cdc920a0Smrgstatic void 335cdc920a0Smrg__glXProcessServerString(const struct extension_info *ext, 336cdc920a0Smrg const char *server_string, 337cdc920a0Smrg unsigned char *server_support) 338cdc920a0Smrg{ 339cdc920a0Smrg unsigned base; 340cdc920a0Smrg unsigned len; 341cdc920a0Smrg 342cdc920a0Smrg for (base = 0; server_string[base] != NUL; /* empty */ ) { 343cdc920a0Smrg /* Determine the length of the next extension name. 344cdc920a0Smrg */ 345cdc920a0Smrg for (len = 0; (server_string[base + len] != SEPARATOR) 346cdc920a0Smrg && (server_string[base + len] != NUL); len++) { 347cdc920a0Smrg /* empty */ 348cdc920a0Smrg } 349cdc920a0Smrg 350cdc920a0Smrg /* Set the bit for the extension in the server_support table. 351cdc920a0Smrg */ 352cdc920a0Smrg set_glx_extension(ext, &server_string[base], len, GL_TRUE, 353cdc920a0Smrg server_support); 354cdc920a0Smrg 355cdc920a0Smrg 356cdc920a0Smrg /* Advance to the next extension string. This means that we skip 357cdc920a0Smrg * over the previous string and any trialing white-space. 358cdc920a0Smrg */ 359cdc920a0Smrg for (base += len; (server_string[base] == SEPARATOR) 360cdc920a0Smrg && (server_string[base] != NUL); base++) { 361cdc920a0Smrg /* empty */ 362cdc920a0Smrg } 363cdc920a0Smrg } 364cdc920a0Smrg} 365cdc920a0Smrg 366cdc920a0Smrgvoid 3673464ebd5Sriastradh__glXEnableDirectExtension(struct glx_screen * psc, const char *name) 368cdc920a0Smrg{ 369cdc920a0Smrg __glXExtensionsCtr(); 370cdc920a0Smrg __glXExtensionsCtrScreen(psc); 371cdc920a0Smrg 372cdc920a0Smrg set_glx_extension(known_glx_extensions, 373cdc920a0Smrg name, strlen(name), GL_TRUE, psc->direct_support); 374cdc920a0Smrg} 375cdc920a0Smrg 376cdc920a0Smrg/** 377cdc920a0Smrg * Initialize global extension support tables. 378cdc920a0Smrg */ 379cdc920a0Smrg 380cdc920a0Smrgstatic void 381cdc920a0Smrg__glXExtensionsCtr(void) 382cdc920a0Smrg{ 383cdc920a0Smrg unsigned i; 384cdc920a0Smrg static GLboolean ext_list_first_time = GL_TRUE; 385cdc920a0Smrg 386cdc920a0Smrg 387cdc920a0Smrg if (ext_list_first_time) { 388cdc920a0Smrg ext_list_first_time = GL_FALSE; 389cdc920a0Smrg 390cdc920a0Smrg (void) memset(client_glx_support, 0, sizeof(client_glx_support)); 391cdc920a0Smrg (void) memset(direct_glx_support, 0, sizeof(direct_glx_support)); 392cdc920a0Smrg (void) memset(client_glx_only, 0, sizeof(client_glx_only)); 393cdc920a0Smrg (void) memset(direct_glx_only, 0, sizeof(direct_glx_only)); 394cdc920a0Smrg 395cdc920a0Smrg (void) memset(client_gl_support, 0, sizeof(client_gl_support)); 396cdc920a0Smrg (void) memset(client_gl_only, 0, sizeof(client_gl_only)); 397cdc920a0Smrg 398cdc920a0Smrg for (i = 0; known_glx_extensions[i].name != NULL; i++) { 399cdc920a0Smrg const unsigned bit = known_glx_extensions[i].bit; 400cdc920a0Smrg 401cdc920a0Smrg if (known_glx_extensions[i].client_support) { 402cdc920a0Smrg SET_BIT(client_glx_support, bit); 403cdc920a0Smrg } 404cdc920a0Smrg 405cdc920a0Smrg if (known_glx_extensions[i].direct_support) { 406cdc920a0Smrg SET_BIT(direct_glx_support, bit); 407cdc920a0Smrg } 408cdc920a0Smrg 409cdc920a0Smrg if (known_glx_extensions[i].client_only) { 410cdc920a0Smrg SET_BIT(client_glx_only, bit); 411cdc920a0Smrg } 412cdc920a0Smrg 413cdc920a0Smrg if (known_glx_extensions[i].direct_only) { 414cdc920a0Smrg SET_BIT(direct_glx_only, bit); 415cdc920a0Smrg } 416cdc920a0Smrg } 417cdc920a0Smrg 418cdc920a0Smrg for (i = 0; known_gl_extensions[i].name != NULL; i++) { 419cdc920a0Smrg const unsigned bit = known_gl_extensions[i].bit; 420cdc920a0Smrg 421cdc920a0Smrg if (known_gl_extensions[i].client_support) { 422cdc920a0Smrg SET_BIT(client_gl_support, bit); 423cdc920a0Smrg } 424cdc920a0Smrg 425cdc920a0Smrg if (known_gl_extensions[i].client_only) { 426cdc920a0Smrg SET_BIT(client_gl_only, bit); 427cdc920a0Smrg } 428cdc920a0Smrg } 429cdc920a0Smrg 430cdc920a0Smrg#if 0 431cdc920a0Smrg fprintf(stderr, "[%s:%u] Maximum client library version: %u.%u\n", 432cdc920a0Smrg __func__, __LINE__, gl_major, gl_minor); 433cdc920a0Smrg#endif 434cdc920a0Smrg } 435cdc920a0Smrg} 436cdc920a0Smrg 437cdc920a0Smrg 438cdc920a0Smrg/** 439cdc920a0Smrg * Make sure that per-screen direct-support table is initialized. 440cdc920a0Smrg * 441cdc920a0Smrg * \param psc Pointer to GLX per-screen record. 442cdc920a0Smrg */ 443cdc920a0Smrg 444cdc920a0Smrgstatic void 4453464ebd5Sriastradh__glXExtensionsCtrScreen(struct glx_screen * psc) 446cdc920a0Smrg{ 447cdc920a0Smrg if (psc->ext_list_first_time) { 448cdc920a0Smrg psc->ext_list_first_time = GL_FALSE; 449cdc920a0Smrg (void) memcpy(psc->direct_support, direct_glx_support, 450cdc920a0Smrg sizeof(direct_glx_support)); 451cdc920a0Smrg } 452cdc920a0Smrg} 453cdc920a0Smrg 454cdc920a0Smrg 455cdc920a0Smrg/** 456cdc920a0Smrg * Check if a certain extension is enabled on a given screen. 457cdc920a0Smrg * 458cdc920a0Smrg * \param psc Pointer to GLX per-screen record. 459cdc920a0Smrg * \param bit Bit index in the direct-support table. 460cdc920a0Smrg * \returns If the extension bit is enabled for the screen, \c GL_TRUE is 461cdc920a0Smrg * returned. If the extension bit is not enabled or if \c psc is 462cdc920a0Smrg * \c NULL, then \c GL_FALSE is returned. 463cdc920a0Smrg */ 464cdc920a0SmrgGLboolean 4653464ebd5Sriastradh__glXExtensionBitIsEnabled(struct glx_screen * psc, unsigned bit) 466cdc920a0Smrg{ 467cdc920a0Smrg GLboolean enabled = GL_FALSE; 468cdc920a0Smrg 469cdc920a0Smrg if (psc != NULL) { 470cdc920a0Smrg __glXExtensionsCtr(); 471cdc920a0Smrg __glXExtensionsCtrScreen(psc); 472cdc920a0Smrg enabled = EXT_ENABLED(bit, psc->direct_support); 473cdc920a0Smrg } 474cdc920a0Smrg 475cdc920a0Smrg return enabled; 476cdc920a0Smrg} 477cdc920a0Smrg 478cdc920a0Smrg 479cdc920a0Smrg/** 480cdc920a0Smrg * Check if a certain extension is enabled in a given context. 481cdc920a0Smrg * 482cdc920a0Smrg */ 483cdc920a0SmrgGLboolean 4843464ebd5Sriastradh__glExtensionBitIsEnabled(struct glx_context *gc, unsigned bit) 485cdc920a0Smrg{ 486cdc920a0Smrg GLboolean enabled = GL_FALSE; 487cdc920a0Smrg 488cdc920a0Smrg if (gc != NULL) { 489cdc920a0Smrg enabled = EXT_ENABLED(bit, gc->gl_extension_bits); 490cdc920a0Smrg } 491cdc920a0Smrg 492cdc920a0Smrg return enabled; 493cdc920a0Smrg} 494cdc920a0Smrg 495cdc920a0Smrg 496cdc920a0Smrg 497cdc920a0Smrg/** 498cdc920a0Smrg * Convert a bit-field to a string of supported extensions. 499cdc920a0Smrg */ 500cdc920a0Smrgstatic char * 501cdc920a0Smrg__glXGetStringFromTable(const struct extension_info *ext, 502cdc920a0Smrg const unsigned char *supported) 503cdc920a0Smrg{ 504cdc920a0Smrg unsigned i; 505cdc920a0Smrg unsigned ext_str_len; 506cdc920a0Smrg char *ext_str; 507cdc920a0Smrg char *point; 508cdc920a0Smrg 509cdc920a0Smrg 510cdc920a0Smrg ext_str_len = 0; 511cdc920a0Smrg for (i = 0; ext[i].name != NULL; i++) { 512cdc920a0Smrg if (EXT_ENABLED(ext[i].bit, supported)) { 513cdc920a0Smrg ext_str_len += ext[i].name_len + 1; 514cdc920a0Smrg } 515cdc920a0Smrg } 516cdc920a0Smrg 517af69d88dSmrg ext_str = malloc(ext_str_len + 1); 518cdc920a0Smrg if (ext_str != NULL) { 519cdc920a0Smrg point = ext_str; 520cdc920a0Smrg 521cdc920a0Smrg for (i = 0; ext[i].name != NULL; i++) { 522cdc920a0Smrg if (EXT_ENABLED(ext[i].bit, supported)) { 523cdc920a0Smrg (void) memcpy(point, ext[i].name, ext[i].name_len); 524cdc920a0Smrg point += ext[i].name_len; 525cdc920a0Smrg 526cdc920a0Smrg *point = ' '; 527cdc920a0Smrg point++; 528cdc920a0Smrg } 529cdc920a0Smrg } 530cdc920a0Smrg 531cdc920a0Smrg *point = '\0'; 532cdc920a0Smrg } 533cdc920a0Smrg 534cdc920a0Smrg return ext_str; 535cdc920a0Smrg} 536cdc920a0Smrg 537cdc920a0Smrg 538cdc920a0Smrg/** 539cdc920a0Smrg * Get the string of client library supported extensions. 540cdc920a0Smrg */ 541cdc920a0Smrgconst char * 542cdc920a0Smrg__glXGetClientExtensions(void) 543cdc920a0Smrg{ 544cdc920a0Smrg if (__glXGLXClientExtensions == NULL) { 545cdc920a0Smrg __glXExtensionsCtr(); 546cdc920a0Smrg __glXGLXClientExtensions = __glXGetStringFromTable(known_glx_extensions, 547cdc920a0Smrg client_glx_support); 548cdc920a0Smrg } 549cdc920a0Smrg 550cdc920a0Smrg return __glXGLXClientExtensions; 551cdc920a0Smrg} 552cdc920a0Smrg 553cdc920a0Smrg 554cdc920a0Smrg/** 555cdc920a0Smrg * Calculate the list of application usable extensions. The resulting 556cdc920a0Smrg * string is stored in \c psc->effectiveGLXexts. 557cdc920a0Smrg * 558cdc920a0Smrg * \param psc Pointer to GLX per-screen record. 559cdc920a0Smrg * \param display_is_direct_capable True if the display is capable of 560cdc920a0Smrg * direct rendering. 561cdc920a0Smrg * \param minor_version GLX minor version from the server. 562cdc920a0Smrg */ 563cdc920a0Smrg 564cdc920a0Smrgvoid 5653464ebd5Sriastradh__glXCalculateUsableExtensions(struct glx_screen * psc, 566cdc920a0Smrg GLboolean display_is_direct_capable, 567cdc920a0Smrg int minor_version) 568cdc920a0Smrg{ 569cdc920a0Smrg unsigned char server_support[8]; 570cdc920a0Smrg unsigned char usable[8]; 571cdc920a0Smrg unsigned i; 572cdc920a0Smrg 573cdc920a0Smrg __glXExtensionsCtr(); 574cdc920a0Smrg __glXExtensionsCtrScreen(psc); 575cdc920a0Smrg 576cdc920a0Smrg (void) memset(server_support, 0, sizeof(server_support)); 577cdc920a0Smrg __glXProcessServerString(known_glx_extensions, 578cdc920a0Smrg psc->serverGLXexts, server_support); 579cdc920a0Smrg 580cdc920a0Smrg 581cdc920a0Smrg /* This is a hack. Some servers support GLX 1.3 but don't export 582cdc920a0Smrg * all of the extensions implied by GLX 1.3. If the server claims 583cdc920a0Smrg * support for GLX 1.3, enable support for the extensions that can be 584cdc920a0Smrg * "emulated" as well. 585cdc920a0Smrg */ 586af69d88dSmrg#ifndef GLX_USE_APPLEGL 587cdc920a0Smrg if (minor_version >= 3) { 588cdc920a0Smrg SET_BIT(server_support, EXT_visual_info_bit); 589cdc920a0Smrg SET_BIT(server_support, EXT_visual_rating_bit); 590cdc920a0Smrg SET_BIT(server_support, SGI_make_current_read_bit); 591cdc920a0Smrg SET_BIT(server_support, SGIX_fbconfig_bit); 592cdc920a0Smrg SET_BIT(server_support, SGIX_pbuffer_bit); 593cdc920a0Smrg 594cdc920a0Smrg /* This one is a little iffy. GLX 1.3 doesn't incorporate all of this 595cdc920a0Smrg * extension. However, the only part that is not strictly client-side 596cdc920a0Smrg * is shared. That's the glXQueryContext / glXQueryContextInfoEXT 597cdc920a0Smrg * function. 598cdc920a0Smrg */ 599cdc920a0Smrg 600cdc920a0Smrg SET_BIT(server_support, EXT_import_context_bit); 601cdc920a0Smrg } 602af69d88dSmrg#endif 603cdc920a0Smrg 604cdc920a0Smrg /* An extension is supported if the client-side (i.e., libGL) supports 605cdc920a0Smrg * it and the "server" supports it. In this case that means that either 606cdc920a0Smrg * the true server supports it or it is only for direct-rendering and 607cdc920a0Smrg * the direct rendering driver supports it. 608cdc920a0Smrg * 609cdc920a0Smrg * If the display is not capable of direct rendering, then the extension 610cdc920a0Smrg * is enabled if and only if the client-side library and the server 611cdc920a0Smrg * support it. 612cdc920a0Smrg */ 613cdc920a0Smrg 614cdc920a0Smrg if (display_is_direct_capable) { 615cdc920a0Smrg for (i = 0; i < 8; i++) { 616cdc920a0Smrg usable[i] = (client_glx_support[i] & client_glx_only[i]) 617cdc920a0Smrg | (client_glx_support[i] & psc->direct_support[i] & 618cdc920a0Smrg server_support[i]) 619cdc920a0Smrg | (client_glx_support[i] & psc->direct_support[i] & 620cdc920a0Smrg direct_glx_only[i]); 621cdc920a0Smrg } 622cdc920a0Smrg } 623cdc920a0Smrg else { 624cdc920a0Smrg for (i = 0; i < 8; i++) { 625cdc920a0Smrg usable[i] = (client_glx_support[i] & client_glx_only[i]) 626cdc920a0Smrg | (client_glx_support[i] & server_support[i]); 627cdc920a0Smrg } 628cdc920a0Smrg } 629cdc920a0Smrg 630af69d88dSmrg /* This hack is necessary because GLX_ARB_create_context_profile depends on 631af69d88dSmrg * server support, but GLX_EXT_create_context_es2_profile is direct-only. 632af69d88dSmrg * Without this hack, it would be possible to advertise 633af69d88dSmrg * GLX_EXT_create_context_es2_profile without 634af69d88dSmrg * GLX_ARB_create_context_profile. That would be a problem. 635af69d88dSmrg */ 636af69d88dSmrg if (!IS_SET(server_support, ARB_create_context_profile_bit)) { 637af69d88dSmrg CLR_BIT(usable, EXT_create_context_es2_profile_bit); 638af69d88dSmrg } 639af69d88dSmrg 640cdc920a0Smrg psc->effectiveGLXexts = __glXGetStringFromTable(known_glx_extensions, 641cdc920a0Smrg usable); 642cdc920a0Smrg} 643cdc920a0Smrg 644cdc920a0Smrg 645cdc920a0Smrg/** 646cdc920a0Smrg * Calculate the list of application usable extensions. The resulting 647cdc920a0Smrg * string is stored in \c gc->extensions. 648cdc920a0Smrg * 649cdc920a0Smrg * \param gc Pointer to GLX context. 650cdc920a0Smrg * \param server_string Extension string from the server. 651cdc920a0Smrg * \param major_version GL major version from the server. 652cdc920a0Smrg * \param minor_version GL minor version from the server. 653cdc920a0Smrg */ 654cdc920a0Smrg 655cdc920a0Smrgvoid 6563464ebd5Sriastradh__glXCalculateUsableGLExtensions(struct glx_context * gc, 657cdc920a0Smrg const char *server_string, 658cdc920a0Smrg int major_version, int minor_version) 659cdc920a0Smrg{ 660cdc920a0Smrg unsigned char server_support[__GL_EXT_BYTES]; 661cdc920a0Smrg unsigned char usable[__GL_EXT_BYTES]; 662cdc920a0Smrg unsigned i; 663cdc920a0Smrg 664cdc920a0Smrg 665cdc920a0Smrg __glXExtensionsCtr(); 666cdc920a0Smrg 667cdc920a0Smrg (void) memset(server_support, 0, sizeof(server_support)); 668cdc920a0Smrg __glXProcessServerString(known_gl_extensions, server_string, 669cdc920a0Smrg server_support); 670cdc920a0Smrg 671cdc920a0Smrg 672cdc920a0Smrg /* Handle lazy servers that don't export all the extensions strings that 673cdc920a0Smrg * are part of the GL core version that they support. 674cdc920a0Smrg */ 675cdc920a0Smrg 676cdc920a0Smrg for (i = 0; i < __GL_EXT_BYTES; i++) { 677cdc920a0Smrg if ((known_gl_extensions[i].version_major != 0) 678cdc920a0Smrg && ((major_version > known_gl_extensions[i].version_major) 679cdc920a0Smrg || ((major_version == known_gl_extensions[i].version_major) 680cdc920a0Smrg && (minor_version >= 681cdc920a0Smrg known_gl_extensions[i].version_minor)))) { 682cdc920a0Smrg SET_BIT(server_support, known_gl_extensions[i].bit); 683cdc920a0Smrg } 684cdc920a0Smrg } 685cdc920a0Smrg 686cdc920a0Smrg 687cdc920a0Smrg /* An extension is supported if the client-side (i.e., libGL) supports 688cdc920a0Smrg * it and the server supports it or the client-side library supports it 689cdc920a0Smrg * and it only needs client-side support. 690cdc920a0Smrg */ 691cdc920a0Smrg 692cdc920a0Smrg for (i = 0; i < __GL_EXT_BYTES; i++) { 693cdc920a0Smrg usable[i] = (client_gl_support[i] & client_gl_only[i]) 694cdc920a0Smrg | (client_gl_support[i] & server_support[i]); 695cdc920a0Smrg } 696cdc920a0Smrg 697cdc920a0Smrg gc->extensions = (unsigned char *) 698cdc920a0Smrg __glXGetStringFromTable(known_gl_extensions, usable); 699cdc920a0Smrg (void) memcpy(gc->gl_extension_bits, usable, sizeof(usable)); 700cdc920a0Smrg} 701cdc920a0Smrg 702cdc920a0Smrg 703cdc920a0Smrg/** 704cdc920a0Smrg * Calculates the maximum core GL version that can be supported for indirect 705cdc920a0Smrg * rendering. 706cdc920a0Smrg */ 707cdc920a0Smrgvoid 708cdc920a0Smrg__glXGetGLVersion(int *major_version, int *minor_version) 709cdc920a0Smrg{ 710cdc920a0Smrg __glXExtensionsCtr(); 711cdc920a0Smrg *major_version = gl_major; 712cdc920a0Smrg *minor_version = gl_minor; 713cdc920a0Smrg} 714cdc920a0Smrg 715cdc920a0Smrg 716cdc920a0Smrg/** 717cdc920a0Smrg * Get a string representing the set of extensions supported by the client 718cdc920a0Smrg * library. This is currently only used to send the list of extensions 719cdc920a0Smrg * supported by the client to the server. 720cdc920a0Smrg */ 721cdc920a0Smrgchar * 722cdc920a0Smrg__glXGetClientGLExtensionString(void) 723cdc920a0Smrg{ 724cdc920a0Smrg __glXExtensionsCtr(); 725cdc920a0Smrg return __glXGetStringFromTable(known_gl_extensions, client_gl_support); 726cdc920a0Smrg} 727