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