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