Entry Points: Auto-generate extensions EPs.
This is partially complete - it is missing the auto-gen for custom
ANGLE and Chromium extensions that aren't present in gl.xml. We
can upstream some of these extensions, but will also need to make
custom handling for some extensions that are too volatile or under-
specced to upstream to Khronos.
This also tweaks some of the Context method names to match what the
auto-generator expects. It also updates some TexStorage entry points.
Also includes a specialized error return value for glTestFenceNV.
Also removes the TexImage3DOES entry point which was neither used
nor accessible to the application.
Bug: angleproject:2263
Change-Id: I3667c22b1b15f84ab4c7dfecb5745aaf73d11e76
Reviewed-on: https://chromium-review.googlesource.com/846420
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/scripts/generate_entry_points.py b/scripts/generate_entry_points.py
index c431ef2..8342b33 100644
--- a/scripts/generate_entry_points.py
+++ b/scripts/generate_entry_points.py
@@ -11,6 +11,41 @@
import xml.etree.ElementTree as etree
from datetime import date
+# List of supported extensions. Add to this list to enable new extensions
+# available in gl.xml.
+# TODO(jmadill): Support extensions not in gl.xml.
+supported_extensions = sorted([
+ "GL_ANGLE_framebuffer_blit",
+ "GL_ANGLE_framebuffer_multisample",
+ "GL_ANGLE_instanced_arrays",
+ "GL_ANGLE_translated_shader_source",
+ "GL_EXT_debug_marker",
+ "GL_EXT_discard_framebuffer",
+ "GL_EXT_disjoint_timer_query",
+ "GL_EXT_draw_buffers",
+ "GL_EXT_map_buffer_range",
+ "GL_EXT_occlusion_query_boolean",
+ "GL_EXT_robustness",
+ "GL_EXT_texture_storage",
+ "GL_KHR_debug",
+ "GL_NV_fence",
+ "GL_OES_EGL_image",
+ "GL_OES_get_program_binary",
+ "GL_OES_mapbuffer",
+ "GL_OES_vertex_array_object",
+])
+
+# This is a list of exceptions for entry points which don't want to have
+# the EVENT macro. This is required for some debug marker entry points.
+no_event_marker_exceptions_list = sorted([
+ "glPushGroupMarkerEXT",
+ "glPopGroupMarkerEXT",
+ "glInsertEventMarkerEXT",
+])
+
+# Strip these suffixes from Context entry point names. NV is excluded (for now).
+strip_suffixes = ["ANGLE", "EXT", "KHR", "OES"]
+
template_entry_point_header = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}.
//
@@ -78,7 +113,7 @@
template_entry_point_def = """{return_type}GL_APIENTRY {name}({params})
{{
- EVENT("({format_params})"{comma_if_needed}{pass_params});
+ {event_comment}EVENT("({format_params})"{comma_if_needed}{pass_params});
Context *context = {context_getter}();
if (context)
@@ -138,7 +173,10 @@
"GLsizeiptr": "%d",
"GLsync": "0x%0.8p",
"GLuint": "%u",
- "GLuint64": "%llu"
+ "GLuint64": "%llu",
+ "GLDEBUGPROC": "0x%0.8p",
+ "GLDEBUGPROCKHR": "0x%0.8p",
+ "GLeglImageOES": "0x%0.8p",
}
def param_format_string(param):
@@ -162,6 +200,10 @@
else:
return "GetValidGlobalContext"
+template_event_comment = """// Don't run an EVENT() macro on the EXT_debug_marker entry points.
+ // It can interfere with the debug events being set by the caller.
+ // """
+
def format_entry_point_def(cmd_name, proto, params):
packed_gl_enums = cmd_packed_gl_enums.get(cmd_name, {})
internal_params = [just_the_name_packed(param, packed_gl_enums) for param in params]
@@ -178,8 +220,13 @@
format_params = [param_format_string(param) for param in params]
return_type = proto[:-len(cmd_name)]
default_return = default_return_value(cmd_name, return_type.strip())
+ event_comment = template_event_comment if cmd_name in no_event_marker_exceptions_list else ""
name_lower_no_suffix = cmd_name[2:3].lower() + cmd_name[3:]
+ for suffix in strip_suffixes:
+ if name_lower_no_suffix.endswith(suffix):
+ name_lower_no_suffix = name_lower_no_suffix[0:-len(suffix)]
+
return template_entry_point_def.format(
name = cmd_name[2:],
name_lower_no_suffix = name_lower_no_suffix,
@@ -193,16 +240,15 @@
format_params = ", ".join(format_params),
return_if_needed = "" if default_return == "" else "return ",
default_return_if_needed = "" if default_return == "" else "\n return " + default_return + ";\n",
- context_getter = get_context_getter_function(cmd_name))
+ context_getter = get_context_getter_function(cmd_name),
+ event_comment = event_comment)
def path_to(folder, file):
return os.path.join(script_relative(".."), "src", folder, file)
def get_entry_points(all_commands, gles_commands):
-
decls = []
defs = []
-
for command in all_commands:
proto = command.find('proto')
cmd_name = proto.find('name').text
@@ -212,7 +258,6 @@
param_text = ["".join(param.itertext()) for param in command.findall('param')]
proto_text = "".join(proto.itertext())
-
decls.append(format_entry_point_decl(cmd_name, proto_text, param_text))
defs.append(format_entry_point_def(cmd_name, proto_text, param_text))
@@ -274,8 +319,79 @@
write_file(annotation, comment, template_entry_point_source,
"\n".join(defs), "cpp", source_includes)
-# TODO(jmadill): Remove manually added entry points once we auto-gen them.
-all_cmd_names += ["glDrawElementsInstancedANGLE"]
+# After we finish with the main entry points, we process the extensions.
+extension_defs = []
+extension_decls = []
+
+# Use a first step to run through the extensions so we can generate them
+# in sorted order.
+ext_data = {}
+
+for extension in root.findall("extensions/extension"):
+ extension_name = extension.attrib['name']
+ if not extension_name in supported_extensions:
+ continue
+
+ 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'] != 'gles2':
+ continue
+
+ # Another 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]
+
+ ext_data[extension_name] = sorted(ext_cmd_names)
+
+for extension_name, ext_cmd_names in sorted(ext_data.iteritems()):
+
+ # Detect and filter duplicate extensions.
+ dupes = []
+ for ext_cmd in ext_cmd_names:
+ if ext_cmd in all_cmd_names:
+ dupes.append(ext_cmd)
+
+ for dupe in dupes:
+ ext_cmd_names.remove(dupe)
+
+ all_cmd_names += ext_cmd_names
+
+ decls, defs = get_entry_points(all_commands, ext_cmd_names)
+
+ # Avoid writing out entry points defined by a prior extension.
+ for dupe in dupes:
+ msg = "// {} is already defined.\n".format(dupe[2:])
+ defs.append(msg)
+
+ # Write the extension name as a comment before the first EP.
+ comment = "\n// {}".format(extension_name)
+ defs.insert(0, comment)
+ decls.insert(0, comment)
+
+ extension_defs += defs
+ extension_decls += decls
+
+header_includes = template_header_includes.format(2, 2, "")
+source_includes = template_sources_includes.format(2, "")
+
+source_includes += """#include "libANGLE/validationES.h"
+#include "libANGLE/validationES3.h"
+#include "libANGLE/validationES31.h"
+"""
+
+write_file("2_0_EXT", "extension", template_entry_point_header,
+ "\n".join([item for item in extension_decls]), "h", header_includes)
+write_file("2_0_EXT", "extension", template_entry_point_source,
+ "\n".join([item for item in extension_defs]), "cpp", source_includes)
sorted_cmd_names = ["Invalid"] + [cmd[2:] for cmd in sorted(all_cmd_names)]