| #!/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. |
| # |
| # generate_loader.py: |
| # Generates dynamic loaders for various binding interfaces. |
| # NOTE: don't run this script directly. Run scripts/run_code_generation.py. |
| |
| import sys, os, pprint, json |
| import registry_xml |
| |
| |
| DEFAULT_INTERNAL_PREFIX = "l_" |
| |
| |
| def write_header(data_source_name, |
| all_cmds, |
| api, |
| preamble, |
| path, |
| lib, |
| ns="", |
| prefix=None, |
| export="", |
| internal_prefix=DEFAULT_INTERNAL_PREFIX, |
| file_prefix=""): |
| file_name = "%s%s_loader_autogen.h" % (file_prefix, api) |
| header_path = registry_xml.path_to(path, file_name) |
| |
| def pre(cmd): |
| if prefix == None: |
| return cmd |
| return prefix + cmd[len(api):] |
| |
| with open(header_path, "w") as out: |
| defines = [ |
| "#define %s%s %s%s%s" % (ns, pre(cmd), internal_prefix, ns, pre(cmd)) |
| for cmd in all_cmds |
| ] |
| var_protos = [ |
| "%sextern PFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd)) |
| for cmd in all_cmds |
| ] |
| loader_header = template_loader_h.format( |
| script_name=os.path.basename(sys.argv[0]), |
| data_source_name=data_source_name, |
| defines="\n".join(defines), |
| function_pointers="\n".join(var_protos), |
| api_upper=api.upper(), |
| api_lower=api, |
| preamble=preamble, |
| export=export, |
| lib=lib.upper(), |
| load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()), |
| file_prefix=file_prefix) |
| |
| out.write(loader_header) |
| out.close() |
| |
| |
| def write_source(data_source_name, |
| all_cmds, |
| api, |
| path, |
| ns="", |
| prefix=None, |
| export="", |
| internal_prefix=DEFAULT_INTERNAL_PREFIX, |
| file_prefix=""): |
| file_name = "%s%s_loader_autogen.cpp" % (file_prefix, api) |
| source_path = registry_xml.path_to(path, file_name) |
| |
| def pre(cmd): |
| if prefix == None: |
| return cmd |
| return prefix + cmd[len(api):] |
| |
| with open(source_path, "w") as out: |
| var_defs = [ |
| "%sPFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd)) |
| for cmd in all_cmds |
| ] |
| |
| setter = " %s%s%s = reinterpret_cast<PFN%sPROC>(loadProc(\"%s\"));" |
| setters = [ |
| setter % (internal_prefix, ns, pre(cmd), cmd.upper(), pre(cmd)) for cmd in all_cmds |
| ] |
| |
| loader_source = template_loader_cpp.format( |
| script_name=os.path.basename(sys.argv[0]), |
| data_source_name=data_source_name, |
| function_pointers="\n".join(var_defs), |
| set_pointers="\n".join(setters), |
| api_upper=api.upper(), |
| api_lower=api, |
| load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()), |
| file_prefix=file_prefix) |
| |
| out.write(loader_source) |
| out.close() |
| |
| |
| def gen_libegl_loader(): |
| |
| data_source_name = "egl.xml and egl_angle_ext.xml" |
| xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml") |
| |
| for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]: |
| annotation = "{}_{}".format(major_version, minor_version) |
| name_prefix = "EGL_VERSION_" |
| |
| feature_name = "{}{}".format(name_prefix, annotation) |
| |
| xml.AddCommands(feature_name, annotation) |
| |
| xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl']) |
| |
| all_cmds = xml.all_cmd_names.get_all_commands() |
| |
| path = os.path.join("..", "src", "libEGL") |
| write_header( |
| data_source_name, |
| all_cmds, |
| "egl", |
| libegl_preamble, |
| path, |
| "LIBEGL", |
| prefix="EGL_", |
| export="ANGLE_NO_EXPORT ") |
| write_source(data_source_name, all_cmds, "egl", path, prefix="EGL_") |
| |
| |
| def gen_gles_loader(gles_preamble, path, header_lib, export, internal_prefix, file_prefix): |
| |
| data_source_name = "gl.xml and gl_angle_ext.xml" |
| xml = registry_xml.RegistryXML("gl.xml", "gl_angle_ext.xml") |
| |
| # First run through the main GLES entry points. Since ES2+ is the primary use |
| # case, we go through those first and then add ES1-only APIs at the end. |
| for major_version, minor_version in [[2, 0], [3, 0], [3, 1], [3, 2], [1, 0]]: |
| annotation = "{}_{}".format(major_version, minor_version) |
| name_prefix = "GL_ES_VERSION_" |
| |
| is_gles1 = major_version == 1 |
| if is_gles1: |
| name_prefix = "GL_VERSION_ES_CM_" |
| |
| feature_name = "{}{}".format(name_prefix, annotation) |
| |
| xml.AddCommands(feature_name, annotation) |
| |
| xml.AddExtensionCommands(registry_xml.supported_extensions, ['gles2', 'gles1']) |
| |
| all_cmds = xml.all_cmd_names.get_all_commands() |
| |
| # Ensure there are no duplicates |
| assert (len(all_cmds) == len(set(all_cmds))), "Duplicate command names found" |
| |
| write_header( |
| data_source_name, |
| all_cmds, |
| "gles", |
| gles_preamble, |
| path, |
| header_lib, |
| export=export, |
| internal_prefix=internal_prefix, |
| file_prefix=file_prefix) |
| write_source( |
| data_source_name, |
| all_cmds, |
| "gles", |
| path, |
| export=export, |
| internal_prefix=internal_prefix, |
| file_prefix=file_prefix) |
| |
| |
| def gen_egl_loader(egl_preamble, path, header_lib, export, internal_prefix, file_prefix): |
| |
| data_source_name = "egl.xml and egl_angle_ext.xml" |
| xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml") |
| |
| for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]: |
| annotation = "{}_{}".format(major_version, minor_version) |
| name_prefix = "EGL_VERSION_" |
| |
| feature_name = "{}{}".format(name_prefix, annotation) |
| |
| xml.AddCommands(feature_name, annotation) |
| |
| xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl']) |
| |
| all_cmds = xml.all_cmd_names.get_all_commands() |
| |
| write_header( |
| data_source_name, |
| all_cmds, |
| "egl", |
| egl_preamble, |
| path, |
| header_lib, |
| export=export, |
| internal_prefix=internal_prefix, |
| file_prefix=file_prefix) |
| write_source( |
| data_source_name, |
| all_cmds, |
| "egl", |
| path, |
| export=export, |
| internal_prefix=internal_prefix, |
| file_prefix=file_prefix) |
| |
| |
| def gen_util_gles_and_egl_loaders(): |
| path = os.path.join("..", "util") |
| export = "ANGLE_UTIL_EXPORT " |
| lib = "UTIL" |
| gen_gles_loader(util_gles_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "") |
| gen_egl_loader(util_egl_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "") |
| |
| |
| def gen_trace_gles_and_egl_loaders(): |
| path = os.path.join("..", "src", "tests", "restricted_traces") |
| export = "ANGLE_TRACE_LOADER_EXPORT " |
| lib = "ANGLE_RESTRICTED_TRACES" |
| gen_gles_loader(trace_gles_preamble, path, lib, export, "t_", "trace_") |
| gen_egl_loader(trace_egl_preamble, path, lib, export, "t_", "trace_") |
| |
| |
| def gen_util_wgl_loader(): |
| |
| supported_wgl_extensions = [ |
| "WGL_ARB_create_context", "WGL_ARB_extensions_string", "WGL_ARB_pixel_format", |
| "WGL_EXT_colorspace", "WGL_EXT_swap_control" |
| ] |
| |
| source = "wgl.xml" |
| xml = registry_xml.RegistryXML(source) |
| |
| for major_version, minor_version in [[1, 0]]: |
| annotation = "{}_{}".format(major_version, minor_version) |
| name_prefix = "WGL_VERSION_" |
| |
| feature_name = "{}{}".format(name_prefix, annotation) |
| |
| xml.AddCommands(feature_name, annotation) |
| |
| xml.AddExtensionCommands(supported_wgl_extensions, ['wgl']) |
| |
| all_cmds = xml.all_cmd_names.get_all_commands() |
| |
| path = os.path.join("..", "util", "windows") |
| write_header(source, all_cmds, "wgl", util_wgl_preamble, path, "UTIL_WINDOWS", "_") |
| write_source(source, all_cmds, "wgl", path, "_") |
| |
| |
| def main(): |
| |
| # Handle inputs/outputs for run_code_generation.py's auto_script |
| if len(sys.argv) > 1: |
| inputs = registry_xml.xml_inputs |
| outputs = [ |
| '../src/libEGL/egl_loader_autogen.cpp', |
| '../src/libEGL/egl_loader_autogen.h', |
| '../util/egl_loader_autogen.cpp', |
| '../util/egl_loader_autogen.h', |
| '../util/gles_loader_autogen.cpp', |
| '../util/gles_loader_autogen.h', |
| '../util/windows/wgl_loader_autogen.cpp', |
| '../util/windows/wgl_loader_autogen.h', |
| '../src/tests/restricted_traces/trace_egl_loader_autogen.cpp', |
| '../src/tests/restricted_traces/trace_egl_loader_autogen.h', |
| '../src/tests/restricted_traces/trace_gles_loader_autogen.cpp', |
| '../src/tests/restricted_traces/trace_gles_loader_autogen.h', |
| ] |
| |
| if sys.argv[1] == 'inputs': |
| print(','.join(inputs)) |
| elif sys.argv[1] == 'outputs': |
| print(','.join(outputs)) |
| else: |
| print('Invalid script parameters') |
| return 1 |
| return 0 |
| |
| gen_libegl_loader() |
| gen_util_gles_and_egl_loaders() |
| gen_util_wgl_loader() |
| gen_trace_gles_and_egl_loaders() |
| return 0 |
| |
| |
| libegl_preamble = """#include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| #include <export.h> |
| """ |
| |
| util_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES |
| #error "Don't define GL prototypes if you want to use a loader!" |
| #endif // defined(GL_GLES_PROTOTYPES) |
| |
| #include "angle_gl.h" |
| #include "util/util_export.h" |
| """ |
| |
| util_egl_preamble = """#include "util/util_export.h" |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| """ |
| |
| trace_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES |
| #error "Don't define GL prototypes if you want to use a loader!" |
| #endif // defined(GL_GLES_PROTOTYPES) |
| |
| #include "angle_gl.h" |
| #include "restricted_traces_export.h" |
| """ |
| |
| trace_egl_preamble = """ |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| |
| #include "restricted_traces_export.h" |
| """ |
| |
| util_wgl_preamble = """ |
| #include <WGL/wgl.h> |
| #include <GLES2/gl2.h> |
| |
| // We add an underscore before each function name to ensure common names like "ChoosePixelFormat" |
| // and "SwapBuffers" don't conflict with our function pointers. We can't use a namespace because |
| // some functions conflict with preprocessor definitions. |
| """ |
| |
| template_loader_h = """// GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name}. |
| // |
| // 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. |
| // |
| // {api_lower}_loader_autogen.h: |
| // Simple {api_upper} function loader. |
| |
| #ifndef {lib}_{api_upper}_LOADER_AUTOGEN_H_ |
| #define {lib}_{api_upper}_LOADER_AUTOGEN_H_ |
| |
| {preamble} |
| {defines} |
| {function_pointers} |
| |
| namespace {file_prefix}angle |
| {{ |
| using GenericProc = void (*)(); |
| using LoadProc = GenericProc (KHRONOS_APIENTRY *)(const char *); |
| {export}void {load_fn_name}(LoadProc loadProc); |
| }} // namespace angle |
| |
| #endif // {lib}_{api_upper}_LOADER_AUTOGEN_H_ |
| """ |
| |
| template_loader_cpp = """// GENERATED FILE - DO NOT EDIT. |
| // Generated by {script_name} using data from {data_source_name}. |
| // |
| // 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. |
| // |
| // {api_lower}_loader_autogen.cpp: |
| // Simple {api_upper} function loader. |
| |
| #include "{file_prefix}{api_lower}_loader_autogen.h" |
| |
| {function_pointers} |
| |
| namespace {file_prefix}angle |
| {{ |
| void {load_fn_name}(LoadProc loadProc) |
| {{ |
| {set_pointers} |
| }} |
| }} // namespace angle |
| """ |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |