1#!/usr/bin/python3 2# 3# Copyright 2018 The ANGLE Project Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# generate_loader.py: 8# Generates dynamic loaders for various binding interfaces. 9# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 10 11import sys, os, pprint, json 12import registry_xml 13 14 15DEFAULT_INTERNAL_PREFIX = "l_" 16 17 18def write_header(data_source_name, 19 all_cmds, 20 api, 21 preamble, 22 path, 23 lib, 24 ns="", 25 prefix=None, 26 export="", 27 internal_prefix=DEFAULT_INTERNAL_PREFIX, 28 file_prefix=""): 29 file_name = "%s%s_loader_autogen.h" % (file_prefix, api) 30 header_path = registry_xml.path_to(path, file_name) 31 32 def pre(cmd): 33 if prefix == None: 34 return cmd 35 return prefix + cmd[len(api):] 36 37 with open(header_path, "w") as out: 38 defines = [ 39 "#define %s%s %s%s%s" % (ns, pre(cmd), internal_prefix, ns, pre(cmd)) 40 for cmd in all_cmds 41 ] 42 var_protos = [ 43 "%sextern PFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd)) 44 for cmd in all_cmds 45 ] 46 loader_header = template_loader_h.format( 47 script_name=os.path.basename(sys.argv[0]), 48 data_source_name=data_source_name, 49 defines="\n".join(defines), 50 function_pointers="\n".join(var_protos), 51 api_upper=api.upper(), 52 api_lower=api, 53 preamble=preamble, 54 export=export, 55 lib=lib.upper(), 56 load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()), 57 file_prefix=file_prefix) 58 59 out.write(loader_header) 60 out.close() 61 62 63def write_source(data_source_name, 64 all_cmds, 65 api, 66 path, 67 ns="", 68 prefix=None, 69 export="", 70 internal_prefix=DEFAULT_INTERNAL_PREFIX, 71 file_prefix=""): 72 file_name = "%s%s_loader_autogen.cpp" % (file_prefix, api) 73 source_path = registry_xml.path_to(path, file_name) 74 75 def pre(cmd): 76 if prefix == None: 77 return cmd 78 return prefix + cmd[len(api):] 79 80 with open(source_path, "w") as out: 81 var_defs = [ 82 "%sPFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd)) 83 for cmd in all_cmds 84 ] 85 86 setter = " %s%s%s = reinterpret_cast<PFN%sPROC>(loadProc(\"%s\"));" 87 setters = [ 88 setter % (internal_prefix, ns, pre(cmd), cmd.upper(), pre(cmd)) for cmd in all_cmds 89 ] 90 91 loader_source = template_loader_cpp.format( 92 script_name=os.path.basename(sys.argv[0]), 93 data_source_name=data_source_name, 94 function_pointers="\n".join(var_defs), 95 set_pointers="\n".join(setters), 96 api_upper=api.upper(), 97 api_lower=api, 98 load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()), 99 file_prefix=file_prefix) 100 101 out.write(loader_source) 102 out.close() 103 104 105def gen_libegl_loader(): 106 107 data_source_name = "egl.xml and egl_angle_ext.xml" 108 xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml") 109 110 for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]: 111 annotation = "{}_{}".format(major_version, minor_version) 112 name_prefix = "EGL_VERSION_" 113 114 feature_name = "{}{}".format(name_prefix, annotation) 115 116 xml.AddCommands(feature_name, annotation) 117 118 xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl']) 119 120 all_cmds = xml.all_cmd_names.get_all_commands() 121 122 path = os.path.join("..", "src", "libEGL") 123 write_header( 124 data_source_name, 125 all_cmds, 126 "egl", 127 libegl_preamble, 128 path, 129 "LIBEGL", 130 prefix="EGL_", 131 export="ANGLE_NO_EXPORT ") 132 write_source(data_source_name, all_cmds, "egl", path, prefix="EGL_") 133 134 135def gen_gles_loader(gles_preamble, path, header_lib, export, internal_prefix, file_prefix): 136 137 data_source_name = "gl.xml and gl_angle_ext.xml" 138 xml = registry_xml.RegistryXML("gl.xml", "gl_angle_ext.xml") 139 140 # First run through the main GLES entry points. Since ES2+ is the primary use 141 # case, we go through those first and then add ES1-only APIs at the end. 142 for major_version, minor_version in [[2, 0], [3, 0], [3, 1], [3, 2], [1, 0]]: 143 annotation = "{}_{}".format(major_version, minor_version) 144 name_prefix = "GL_ES_VERSION_" 145 146 is_gles1 = major_version == 1 147 if is_gles1: 148 name_prefix = "GL_VERSION_ES_CM_" 149 150 feature_name = "{}{}".format(name_prefix, annotation) 151 152 xml.AddCommands(feature_name, annotation) 153 154 xml.AddExtensionCommands(registry_xml.supported_extensions, ['gles2', 'gles1']) 155 156 all_cmds = xml.all_cmd_names.get_all_commands() 157 158 # Ensure there are no duplicates 159 assert (len(all_cmds) == len(set(all_cmds))), "Duplicate command names found" 160 161 write_header( 162 data_source_name, 163 all_cmds, 164 "gles", 165 gles_preamble, 166 path, 167 header_lib, 168 export=export, 169 internal_prefix=internal_prefix, 170 file_prefix=file_prefix) 171 write_source( 172 data_source_name, 173 all_cmds, 174 "gles", 175 path, 176 export=export, 177 internal_prefix=internal_prefix, 178 file_prefix=file_prefix) 179 180 181def gen_egl_loader(egl_preamble, path, header_lib, export, internal_prefix, file_prefix): 182 183 data_source_name = "egl.xml and egl_angle_ext.xml" 184 xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml") 185 186 for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]: 187 annotation = "{}_{}".format(major_version, minor_version) 188 name_prefix = "EGL_VERSION_" 189 190 feature_name = "{}{}".format(name_prefix, annotation) 191 192 xml.AddCommands(feature_name, annotation) 193 194 xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl']) 195 196 all_cmds = xml.all_cmd_names.get_all_commands() 197 198 write_header( 199 data_source_name, 200 all_cmds, 201 "egl", 202 egl_preamble, 203 path, 204 header_lib, 205 export=export, 206 internal_prefix=internal_prefix, 207 file_prefix=file_prefix) 208 write_source( 209 data_source_name, 210 all_cmds, 211 "egl", 212 path, 213 export=export, 214 internal_prefix=internal_prefix, 215 file_prefix=file_prefix) 216 217 218def gen_util_gles_and_egl_loaders(): 219 path = os.path.join("..", "util") 220 export = "ANGLE_UTIL_EXPORT " 221 lib = "UTIL" 222 gen_gles_loader(util_gles_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "") 223 gen_egl_loader(util_egl_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "") 224 225 226def gen_trace_gles_and_egl_loaders(): 227 path = os.path.join("..", "src", "tests", "restricted_traces") 228 export = "ANGLE_TRACE_LOADER_EXPORT " 229 lib = "ANGLE_RESTRICTED_TRACES" 230 gen_gles_loader(trace_gles_preamble, path, lib, export, "t_", "trace_") 231 gen_egl_loader(trace_egl_preamble, path, lib, export, "t_", "trace_") 232 233 234def gen_util_wgl_loader(): 235 236 supported_wgl_extensions = [ 237 "WGL_ARB_create_context", 238 "WGL_ARB_extensions_string", 239 "WGL_EXT_swap_control", 240 ] 241 242 source = "wgl.xml" 243 xml = registry_xml.RegistryXML(source) 244 245 for major_version, minor_version in [[1, 0]]: 246 annotation = "{}_{}".format(major_version, minor_version) 247 name_prefix = "WGL_VERSION_" 248 249 feature_name = "{}{}".format(name_prefix, annotation) 250 251 xml.AddCommands(feature_name, annotation) 252 253 xml.AddExtensionCommands(supported_wgl_extensions, ['wgl']) 254 255 all_cmds = xml.all_cmd_names.get_all_commands() 256 257 path = os.path.join("..", "util", "windows") 258 write_header(source, all_cmds, "wgl", util_wgl_preamble, path, "UTIL_WINDOWS", "_") 259 write_source(source, all_cmds, "wgl", path, "_") 260 261 262def main(): 263 264 # Handle inputs/outputs for run_code_generation.py's auto_script 265 if len(sys.argv) > 1: 266 inputs = registry_xml.xml_inputs 267 outputs = [ 268 '../src/libEGL/egl_loader_autogen.cpp', 269 '../src/libEGL/egl_loader_autogen.h', 270 '../util/egl_loader_autogen.cpp', 271 '../util/egl_loader_autogen.h', 272 '../util/gles_loader_autogen.cpp', 273 '../util/gles_loader_autogen.h', 274 '../util/windows/wgl_loader_autogen.cpp', 275 '../util/windows/wgl_loader_autogen.h', 276 '../src/tests/restricted_traces/trace_egl_loader_autogen.cpp', 277 '../src/tests/restricted_traces/trace_egl_loader_autogen.h', 278 '../src/tests/restricted_traces/trace_gles_loader_autogen.cpp', 279 '../src/tests/restricted_traces/trace_gles_loader_autogen.h', 280 ] 281 282 if sys.argv[1] == 'inputs': 283 print(','.join(inputs)) 284 elif sys.argv[1] == 'outputs': 285 print(','.join(outputs)) 286 else: 287 print('Invalid script parameters') 288 return 1 289 return 0 290 291 gen_libegl_loader() 292 gen_util_gles_and_egl_loaders() 293 gen_util_wgl_loader() 294 gen_trace_gles_and_egl_loaders() 295 return 0 296 297 298libegl_preamble = """#include <EGL/egl.h> 299#include <EGL/eglext.h> 300#include <export.h> 301""" 302 303util_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES 304#error "Don't define GL prototypes if you want to use a loader!" 305#endif // defined(GL_GLES_PROTOTYPES) 306 307#include "angle_gl.h" 308#include "util/util_export.h" 309""" 310 311util_egl_preamble = """#include "util/util_export.h" 312 313#include <EGL/egl.h> 314#include <EGL/eglext.h> 315""" 316 317trace_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES 318#error "Don't define GL prototypes if you want to use a loader!" 319#endif // defined(GL_GLES_PROTOTYPES) 320 321#include "angle_gl.h" 322#include "restricted_traces_autogen.h" 323""" 324 325trace_egl_preamble = """#include "restricted_traces_autogen.h" 326 327#include <EGL/egl.h> 328#include <EGL/eglext.h> 329""" 330 331util_wgl_preamble = """ 332#include <WGL/wgl.h> 333#include <GLES2/gl2.h> 334 335// We add an underscore before each function name to ensure common names like "ChoosePixelFormat" 336// and "SwapBuffers" don't conflict with our function pointers. We can't use a namespace because 337// some functions conflict with preprocessor definitions. 338""" 339 340template_loader_h = """// GENERATED FILE - DO NOT EDIT. 341// Generated by {script_name} using data from {data_source_name}. 342// 343// Copyright 2018 The ANGLE Project Authors. All rights reserved. 344// Use of this source code is governed by a BSD-style license that can be 345// found in the LICENSE file. 346// 347// {api_lower}_loader_autogen.h: 348// Simple {api_upper} function loader. 349 350#ifndef {lib}_{api_upper}_LOADER_AUTOGEN_H_ 351#define {lib}_{api_upper}_LOADER_AUTOGEN_H_ 352 353{preamble} 354{defines} 355{function_pointers} 356 357namespace {file_prefix}angle 358{{ 359using GenericProc = void (*)(); 360using LoadProc = GenericProc (KHRONOS_APIENTRY *)(const char *); 361{export}void {load_fn_name}(LoadProc loadProc); 362}} // namespace angle 363 364#endif // {lib}_{api_upper}_LOADER_AUTOGEN_H_ 365""" 366 367template_loader_cpp = """// GENERATED FILE - DO NOT EDIT. 368// Generated by {script_name} using data from {data_source_name}. 369// 370// Copyright 2018 The ANGLE Project Authors. All rights reserved. 371// Use of this source code is governed by a BSD-style license that can be 372// found in the LICENSE file. 373// 374// {api_lower}_loader_autogen.cpp: 375// Simple {api_upper} function loader. 376 377#include "{file_prefix}{api_lower}_loader_autogen.h" 378 379{function_pointers} 380 381namespace {file_prefix}angle 382{{ 383void {load_fn_name}(LoadProc loadProc) 384{{ 385{set_pointers} 386}} 387}} // namespace angle 388""" 389 390if __name__ == '__main__': 391 sys.exit(main()) 392