#!/usr/bin/python3 # # Copyright 2018 The ANGLE Project Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # # registry_xml.py: # Parses information from Khronos registry files.. # List of supported extensions. Add to this list to enable new extensions # available in gl.xml. import difflib import os import sys import xml.etree.ElementTree as etree from enum import Enum xml_inputs = [ 'cl.xml', 'gl.xml', 'gl_angle_ext.xml', 'egl.xml', 'egl_angle_ext.xml', 'wgl.xml', 'glx.xml', 'registry_xml.py', ] # Notes on categories of extensions: # 'Requestable' extensions are extensions that can be enabled with ANGLE_request_extension # 'ES-Only' extensions are always implicitly enabled. # 'Toggleable' extensions are like 'Requestable' except they can be also disabled. # 'ANGLE' extensions are extensions that are not yet officially upstreamed to Khronos. # We document those extensions in gl_angle_ext.xml instead of the canonical gl.xml. angle_toggleable_extensions = [ "GL_ANGLE_texture_rectangle", ] angle_requestable_extensions = [ "GL_ANGLE_base_vertex_base_instance", "GL_ANGLE_base_vertex_base_instance_shader_builtin", "GL_ANGLE_compressed_texture_etc", "GL_ANGLE_copy_texture_3d", "GL_ANGLE_framebuffer_multisample", "GL_ANGLE_get_image", "GL_ANGLE_get_tex_level_parameter", "GL_ANGLE_lossy_etc_decode", "GL_ANGLE_memory_object_flags", "GL_ANGLE_memory_object_fuchsia", "GL_ANGLE_memory_size", "GL_ANGLE_multi_draw", "GL_ANGLE_multiview_multisample", "GL_ANGLE_provoking_vertex", "GL_ANGLE_read_only_depth_stencil_feedback_loops", "GL_ANGLE_robust_fragment_shader_output", "GL_ANGLE_semaphore_fuchsia", "GL_ANGLE_texture_compression_dxt3", "GL_ANGLE_texture_compression_dxt5", "GL_ANGLE_texture_external_update", "GL_ANGLE_texture_multisample", "GL_ANGLE_vulkan_image", "GL_ANGLE_yuv_internal_format", "GL_CHROMIUM_color_buffer_float_rgb", "GL_CHROMIUM_color_buffer_float_rgba", "GL_CHROMIUM_lose_context", "GL_CHROMIUM_sync_query", "GL_CHROMIUM_texture_filtering_hint", ] gles_requestable_extensions = [ "GL_ANGLE_framebuffer_blit", "GL_ANGLE_instanced_arrays", "GL_ANGLE_pack_reverse_row_order", "GL_ANGLE_texture_usage", "GL_APPLE_clip_distance", "GL_ARB_sync", "GL_EXT_base_instance", "GL_EXT_blend_func_extended", "GL_EXT_blend_minmax", "GL_EXT_buffer_storage", "GL_EXT_clip_control", "GL_EXT_clip_cull_distance", "GL_EXT_color_buffer_float", "GL_EXT_color_buffer_half_float", "GL_EXT_compressed_ETC1_RGB8_sub_texture", "GL_EXT_copy_image", "GL_EXT_disjoint_timer_query", "GL_EXT_draw_buffers", "GL_EXT_draw_buffers_indexed", "GL_EXT_draw_elements_base_vertex", "GL_EXT_EGL_image_array", "GL_EXT_EGL_image_external_wrap_modes", "GL_EXT_EGL_image_storage", "GL_EXT_external_buffer", "GL_EXT_float_blend", "GL_EXT_frag_depth", "GL_EXT_geometry_shader", "GL_EXT_gpu_shader5", "GL_EXT_instanced_arrays", "GL_EXT_map_buffer_range", "GL_EXT_memory_object", "GL_EXT_memory_object_fd", "GL_EXT_multi_draw_indirect", "GL_EXT_multisampled_render_to_texture", "GL_EXT_multisampled_render_to_texture2", "GL_EXT_occlusion_query_boolean", "GL_EXT_protected_textures", "GL_EXT_pvrtc_sRGB", "GL_EXT_read_format_bgra", "GL_EXT_semaphore", "GL_EXT_semaphore_fd", "GL_EXT_separate_shader_objects", "GL_EXT_shader_framebuffer_fetch", "GL_EXT_shader_framebuffer_fetch_non_coherent", "GL_EXT_shader_io_blocks", "GL_EXT_shader_non_constant_global_initializers", "GL_EXT_shader_texture_lod", "GL_EXT_shadow_samplers", "GL_EXT_sRGB", "GL_EXT_tessellation_shader", "GL_EXT_texture_border_clamp", "GL_EXT_texture_buffer", "GL_EXT_texture_compression_bptc", "GL_EXT_texture_compression_dxt1", "GL_EXT_texture_compression_rgtc", "GL_EXT_texture_compression_s3tc", "GL_EXT_texture_compression_s3tc_srgb", "GL_EXT_texture_cube_map_array", "GL_EXT_texture_filter_anisotropic", "GL_EXT_texture_format_BGRA8888", "GL_EXT_texture_norm16", "GL_EXT_texture_rg", "GL_EXT_texture_sRGB_R8", "GL_EXT_texture_sRGB_RG8", "GL_EXT_texture_storage", "GL_EXT_texture_type_2_10_10_10_REV", "GL_EXT_unpack_subimage", "GL_EXT_YUV_target", "GL_IMG_texture_compression_pvrtc", "GL_IMG_texture_compression_pvrtc2", "GL_KHR_parallel_shader_compile", "GL_KHR_texture_compression_astc_hdr", "GL_KHR_texture_compression_astc_ldr", "GL_KHR_texture_compression_astc_sliced_3d", "GL_MESA_framebuffer_flip_y", "GL_NV_depth_buffer_float2", "GL_NV_EGL_stream_consumer_external", "GL_NV_framebuffer_blit", "GL_NV_pack_subimage", "GL_NV_pixel_buffer_object", "GL_NV_read_depth", "GL_NV_read_depth_stencil", "GL_NV_read_stencil", "GL_NV_shader_noperspective_interpolation", "GL_OES_compressed_EAC_R11_signed_texture", "GL_OES_compressed_EAC_R11_unsigned_texture", "GL_OES_compressed_EAC_RG11_signed_texture", "GL_OES_compressed_EAC_RG11_unsigned_texture", "GL_OES_compressed_ETC1_RGB8_texture", "GL_OES_compressed_ETC2_punchthroughA_RGBA8_texture", "GL_OES_compressed_ETC2_punchthroughA_sRGB8_alpha_texture", "GL_OES_compressed_ETC2_RGB8_texture", "GL_OES_compressed_ETC2_RGBA8_texture", "GL_OES_compressed_ETC2_sRGB8_alpha8_texture", "GL_OES_compressed_ETC2_sRGB8_texture", "GL_OES_copy_image", "GL_OES_depth_texture_cube_map", "GL_OES_draw_buffers_indexed", "GL_OES_draw_elements_base_vertex", "GL_OES_EGL_image", "GL_OES_EGL_image_external", "GL_OES_EGL_image_external_essl3", "GL_OES_element_index_uint", "GL_OES_fbo_render_mipmap", "GL_OES_geometry_shader", "GL_OES_get_program_binary", "GL_OES_mapbuffer", "GL_OES_rgb8_rgba8", "GL_OES_sample_shading", "GL_OES_sample_variables", "GL_OES_shader_image_atomic", "GL_OES_shader_io_blocks", "GL_OES_shader_multisample_interpolation", "GL_OES_standard_derivatives", "GL_OES_texture_3D", "GL_OES_texture_border_clamp", "GL_OES_texture_buffer", "GL_OES_texture_compression_astc", "GL_OES_texture_cube_map_array", "GL_OES_texture_float", "GL_OES_texture_float_linear", "GL_OES_texture_half_float", "GL_OES_texture_half_float_linear", "GL_OES_texture_npot", "GL_OES_texture_stencil8", "GL_OES_texture_storage_multisample_2d_array", "GL_OES_vertex_array_object", "GL_OES_vertex_half_float", "GL_OES_vertex_type_10_10_10_2", "GL_OVR_multiview", "GL_OVR_multiview2", "GL_QCOM_shading_rate", "GL_WEBGL_video_texture", ] angle_es_only_extensions = [ "GL_ANGLE_client_arrays", "GL_ANGLE_get_serialized_context_string", "GL_ANGLE_program_binary", "GL_ANGLE_program_cache_control", "GL_ANGLE_relaxed_vertex_attribute_type", "GL_ANGLE_request_extension", "GL_ANGLE_rgbx_internal_format", "GL_ANGLE_robust_client_memory", "GL_ANGLE_robust_resource_initialization", "GL_ANGLE_shader_pixel_local_storage", "GL_ANGLE_shader_pixel_local_storage_coherent", "GL_ANGLE_webgl_compatibility", "GL_CHROMIUM_bind_generates_resource", "GL_CHROMIUM_bind_uniform_location", "GL_CHROMIUM_copy_compressed_texture", "GL_CHROMIUM_copy_texture", "GL_CHROMIUM_framebuffer_mixed_samples", ] gles_es_only_extensions = [ "GL_AMD_performance_monitor", "GL_ANDROID_extension_pack_es31a", "GL_ANGLE_depth_texture", "GL_ANGLE_translated_shader_source", "GL_EXT_debug_label", "GL_EXT_debug_marker", "GL_EXT_discard_framebuffer", "GL_EXT_multisample_compatibility", "GL_EXT_primitive_bounding_box", "GL_EXT_robustness", "GL_EXT_sRGB_write_control", "GL_EXT_texture_format_sRGB_override", "GL_EXT_texture_sRGB_decode", "GL_KHR_blend_equation_advanced", "GL_KHR_debug", "GL_KHR_no_error", "GL_KHR_robust_buffer_access_behavior", "GL_NV_fence", "GL_NV_robustness_video_memory_purge", "GL_OES_depth24", "GL_OES_depth32", "GL_OES_depth_texture", "GL_OES_EGL_sync", "GL_OES_packed_depth_stencil", "GL_OES_primitive_bounding_box", "GL_OES_surfaceless_context", ] # ES1 (Possibly the min set of extensions needed by Android) gles1_extensions = [ "GL_OES_draw_texture", "GL_OES_framebuffer_object", "GL_OES_matrix_palette", "GL_OES_point_size_array", "GL_OES_point_sprite", "GL_OES_query_matrix", "GL_OES_texture_cube_map", ] def check_sorted(name, l): unidiff = difflib.unified_diff(l, sorted(l, key=str.casefold), 'unsorted', 'sorted') diff_lines = list(unidiff) assert not diff_lines, '\n\nPlease sort "%s":\n%s' % (name, '\n'.join(diff_lines)) angle_extensions = angle_requestable_extensions + angle_es_only_extensions + angle_toggleable_extensions gles_extensions = gles_requestable_extensions + gles_es_only_extensions supported_extensions = sorted(angle_extensions + gles1_extensions + gles_extensions) assert len(supported_extensions) == len(set(supported_extensions)), 'Duplicates in extension list' check_sorted('angle_requestable_extensions', angle_requestable_extensions) check_sorted('angle_es_only_extensions', angle_es_only_extensions) check_sorted('angle_toggleable_extensions', angle_toggleable_extensions) check_sorted('gles_requestable_extensions', gles_requestable_extensions) check_sorted('gles_es_only_extensions', gles_es_only_extensions) check_sorted('gles_extensions', gles1_extensions) supported_egl_extensions = [ "EGL_ANDROID_blob_cache", "EGL_ANDROID_create_native_client_buffer", "EGL_ANDROID_framebuffer_target", "EGL_ANDROID_get_frame_timestamps", "EGL_ANDROID_get_native_client_buffer", "EGL_ANDROID_native_fence_sync", "EGL_ANDROID_presentation_time", "EGL_ANGLE_create_surface_swap_interval", "EGL_ANGLE_d3d_share_handle_client_buffer", "EGL_ANGLE_device_creation", "EGL_ANGLE_device_d3d", "EGL_ANGLE_display_semaphore_share_group", "EGL_ANGLE_display_texture_share_group", "EGL_ANGLE_feature_control", "EGL_ANGLE_ggp_stream_descriptor", "EGL_ANGLE_metal_create_context_ownership_identity", "EGL_ANGLE_power_preference", "EGL_ANGLE_prepare_swap_buffers", "EGL_ANGLE_program_cache_control", "EGL_ANGLE_query_surface_pointer", "EGL_ANGLE_stream_producer_d3d_texture", "EGL_ANGLE_surface_d3d_texture_2d_share_handle", "EGL_ANGLE_swap_with_frame_token", "EGL_ANGLE_sync_control_rate", "EGL_ANGLE_vulkan_image", "EGL_ANGLE_window_fixed_size", "EGL_CHROMIUM_sync_control", "EGL_EXT_create_context_robustness", "EGL_EXT_device_query", "EGL_EXT_gl_colorspace_display_p3", "EGL_EXT_gl_colorspace_display_p3_linear", "EGL_EXT_gl_colorspace_display_p3_passthrough", "EGL_EXT_gl_colorspace_scrgb", "EGL_EXT_gl_colorspace_scrgb_linear", "EGL_EXT_image_dma_buf_import", "EGL_EXT_image_dma_buf_import_modifiers", "EGL_EXT_image_gl_colorspace", "EGL_EXT_pixel_format_float", "EGL_EXT_platform_base", "EGL_EXT_platform_device", "EGL_EXT_protected_content", "EGL_IMG_context_priority", "EGL_KHR_debug", "EGL_KHR_fence_sync", "EGL_KHR_gl_colorspace", "EGL_KHR_image", "EGL_KHR_lock_surface3", "EGL_KHR_mutable_render_buffer", "EGL_KHR_no_config_context", "EGL_KHR_partial_update", "EGL_KHR_reusable_sync", "EGL_KHR_stream", "EGL_KHR_stream_consumer_gltexture", "EGL_KHR_surfaceless_context", "EGL_KHR_swap_buffers_with_damage", "EGL_KHR_wait_sync", "EGL_NV_post_sub_buffer", "EGL_NV_stream_consumer_gltexture_yuv", ] check_sorted('supported_egl_extensions', supported_egl_extensions) supported_cl_extensions = [ # Since OpenCL 1.1 "cl_khr_byte_addressable_store", "cl_khr_global_int32_base_atomics", "cl_khr_global_int32_extended_atomics", "cl_khr_local_int32_base_atomics", "cl_khr_local_int32_extended_atomics", # OpenCL 2.0 - 2.2 "cl_khr_3d_image_writes", "cl_khr_depth_images", "cl_khr_image2d_from_buffer", # Optional "cl_khr_extended_versioning", "cl_khr_fp64", "cl_khr_icd", "cl_khr_int64_base_atomics", "cl_khr_int64_extended_atomics", ] # Strip these suffixes from Context entry point names. NV is excluded (for now). strip_suffixes = ["AMD", "ANDROID", "ANGLE", "CHROMIUM", "EXT", "KHR", "OES", "OVR"] check_sorted('strip_suffixes', strip_suffixes) # The EGL_ANGLE_explicit_context extension is generated differently from other extensions. # Toggle generation here. support_EGL_ANGLE_explicit_context = True # For ungrouped GLenum types default_enum_group_name = "DefaultGroup" # Group names that appear in command/param, but not present in groups/group unsupported_enum_group_names = { 'GetMultisamplePNameNV', 'BufferPNameARB', 'BufferPointerNameARB', 'VertexAttribPointerPropertyARB', 'VertexAttribPropertyARB', 'FenceParameterNameNV', 'FenceConditionNV', 'BufferPointerNameARB', 'MatrixIndexPointerTypeARB', 'PointParameterNameARB', 'ClampColorTargetARB', 'ClampColorModeARB', } # Versions (major, minor). Note that GLES intentionally places 1.0 last. DESKTOP_GL_VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (3, 3), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6)] GLES_VERSIONS = [(2, 0), (3, 0), (3, 1), (3, 2), (1, 0)] EGL_VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5)] WGL_VERSIONS = [(1, 0)] GLX_VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4)] CL_VERSIONS = [(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0)] # API types class apis: GL = 'GL' GLES = 'GLES' WGL = 'WGL' GLX = 'GLX' EGL = 'EGL' CL = 'CL' def script_relative(path): return os.path.join(os.path.dirname(sys.argv[0]), path) def path_to(folder, file): return os.path.join(script_relative(".."), "src", folder, file) def strip_api_prefix(cmd_name): return cmd_name.lstrip("cwegl") def get_cmd_name(command_node): proto = command_node.find('proto') cmd_name = proto.find('name').text return cmd_name class CommandNames: def __init__(self): self.command_names = {} def get_commands(self, version): return self.command_names[version] def get_all_commands(self): cmd_names = [] # Combine all the version lists into a single list for version, version_cmd_names in sorted(self.command_names.items()): cmd_names += version_cmd_names return cmd_names def add_commands(self, version, commands): # Add key if it doesn't exist if version not in self.command_names: self.command_names[version] = [] # Add the commands that aren't duplicates self.command_names[version] += commands class RegistryXML: def __init__(self, xml_file, ext_file=None): tree = etree.parse(script_relative(xml_file)) self.root = tree.getroot() if (ext_file): self._AppendANGLEExts(ext_file) self.all_commands = self.root.findall('commands/command') self.all_cmd_names = CommandNames() self.commands = {} def _AppendANGLEExts(self, ext_file): angle_ext_tree = etree.parse(script_relative(ext_file)) angle_ext_root = angle_ext_tree.getroot() insertion_point = self.root.findall("./commands")[0] for command in angle_ext_root.iter('commands'): insertion_point.extend(command) insertion_point = self.root.findall("./extensions")[0] for extension in angle_ext_root.iter('extensions'): insertion_point.extend(extension) insertion_point = self.root for enums in angle_ext_root.iter('enums'): insertion_point.append(enums) def AddCommands(self, feature_name, annotation): xpath = ".//feature[@name='%s']//command" % feature_name commands = [cmd.attrib['name'] for cmd in self.root.findall(xpath)] # Remove commands that have already been processed current_cmds = self.all_cmd_names.get_all_commands() commands = [cmd for cmd in commands if cmd not in current_cmds] self.all_cmd_names.add_commands(annotation, commands) self.commands[annotation] = commands def _ClassifySupport(self, extension): supported = extension.attrib['supported'] if 'gles2' in supported: return 'gl2ext' elif 'gles1' in supported: return 'glext' elif 'egl' in supported: return 'eglext' elif 'wgl' in supported: return 'wglext' elif 'glx' in supported: return 'glxext' elif 'cl' in supported: return 'clext' else: assert False, 'Cannot classify support for %s: %s' % (extension.attrib['name'], supported) return 'unknown' def AddExtensionCommands(self, supported_extensions, apis): # Use a first step to run through the extensions so we can generate them # in sorted order. self.ext_data = {} self.ext_dupes = {} ext_annotations = {} for extension in self.root.findall("extensions/extension"): extension_name = extension.attrib['name'] if not extension_name in supported_extensions: continue ext_annotations[extension_name] = self._ClassifySupport(extension) ext_cmd_names = [] # There's an extra step here to filter out 'api=gl' extensions. This # is necessary for handling KHR extensions, which have separate entry # point signatures (without the suffix) for desktop GL. Note that this # extra step is necessary because of Etree's limited Xpath support. for require in extension.findall('require'): if 'api' in require.attrib and require.attrib['api'] not in apis: continue # A special case for EXT_texture_storage filter_out_comment = "Supported only if GL_EXT_direct_state_access is supported" if 'comment' in require.attrib and require.attrib['comment'] == filter_out_comment: continue extension_commands = require.findall('command') ext_cmd_names += [command.attrib['name'] for command in extension_commands] self.ext_data[extension_name] = sorted(ext_cmd_names) for extension_name, ext_cmd_names in sorted(self.ext_data.items()): # Detect and filter duplicate extensions. dupes = [] for ext_cmd in ext_cmd_names: if ext_cmd in self.all_cmd_names.get_all_commands(): dupes.append(ext_cmd) for dupe in dupes: ext_cmd_names.remove(dupe) self.ext_data[extension_name] = sorted(ext_cmd_names) self.ext_dupes[extension_name] = dupes self.all_cmd_names.add_commands(ext_annotations[extension_name], ext_cmd_names) class EntryPoints: def __init__(self, api, xml, commands): self.api = api self._cmd_info = [] for command_node in xml.all_commands: cmd_name = get_cmd_name(command_node) if api == apis.WGL: cmd_name = cmd_name if cmd_name.startswith('wgl') else 'wgl' + cmd_name if cmd_name not in commands: continue param_text = ["".join(param.itertext()) for param in command_node.findall('param')] # Treat (void) as () if len(param_text) == 1 and param_text[0].strip() == 'void': param_text = [] proto = command_node.find('proto') proto_text = "".join(proto.itertext()) self._cmd_info.append((cmd_name, command_node, param_text, proto_text)) def get_infos(self): return self._cmd_info