3 # Copyright 2015 The Android Open Source Project
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Utility functions used to parse a list of DLL entry points.
20 # <empty-line> -> ignored
21 # #<comment> -> ignored
22 # %<verbatim> -> verbatim output for header files.
23 # !<prefix> -> prefix name for header files.
24 # <return-type> <function-name> <signature> ; -> entry point declaration.
26 # Anything else is an error.
28 from __future__ import print_function
33 re_func = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)\((.*)\);$""")
34 re_param = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)$""")
36 def eprint(*args, **kwargs):
37 print(*args, file=sys.stderr, **kwargs)
40 """Small class used to model a single DLL entry point."""
41 def __init__(self, func_name, return_type, parameters):
42 """Initialize Entry instance. |func_name| is the function name,
43 |return_type| its return type, and |parameters| is a list of
44 (type,name) tuples from the entry's signature.
46 self.func_name = func_name
47 self.return_type = return_type
53 for param in parameters:
54 self.vartypes.append(param[0])
55 self.varnames.append(param[1])
56 self.parameters += "%s%s %s" % (comma, param[0], param[1])
57 self.call += "%s%s" % (comma, param[1])
60 def banner_command(argv):
61 """Return sanitized command-line description.
62 |argv| must be a list of command-line parameters, e.g. sys.argv.
63 Return a string corresponding to the command, with platform-specific
66 # Remove path from first parameter
68 argv[0] = "android/scripts/gen-entries.py"
71 def parse_entries_file(lines):
72 """Parse an .entries file and return a tuple of:
73 entries: list of Entry instances from the file.
74 prefix_name: prefix name from the file, or None.
75 verbatim: list of verbatim lines from the file.
76 errors: list of errors in the file, prefixed by line number.
86 if len(line) == 0: # Ignore empty lines
88 if line[0] == '#': # Ignore comments
90 if line[0] == '!': # Prefix name
91 prefix_name = line[1:]
93 if line[0] == '%': # Verbatim line copy
94 verbatim.append(line[1:])
96 # Must be a function signature.
97 m = re_func.match(line)
99 errors.append("%d: '%s'" % (lineno, line))
102 return_type, func_name, parameters = m.groups()
103 return_type = return_type.strip()
104 parameters = parameters.strip()
107 if parameters != "void":
108 for parameter in parameters.split(','):
109 parameter = parameter.strip()
110 m = re_param.match(parameter)
112 errors.append("%d: parameter '%s'" % (lineno, parameter))
116 param_type, param_name = m.groups()
117 params.append((param_type.strip(), param_name.strip()))
120 entries.append(Entry(func_name, return_type, params))
122 return (entries, prefix_name, verbatim, errors)
125 def gen_functions_header(entries, prefix_name, verbatim, filename, with_args):
126 """Generate a C header containing a macro listing all entry points.
127 |entries| is a list of Entry instances.
128 |prefix_name| is a prefix-name, it will be converted to upper-case.
129 |verbatim| is a list of verbatim lines that must appear before the
130 macro declaration. Useful to insert #include <> statements.
131 |filename| is the name of the original file.
133 prefix_name = prefix_name.upper()
135 print("// Auto-generated with: %s" % banner_command(sys.argv))
136 print("// DO NOT EDIT THIS FILE")
138 print("#ifndef %s_FUNCTIONS_H" % prefix_name)
139 print("#define %s_FUNCTIONS_H" % prefix_name)
141 for line in verbatim:
144 print("#define LIST_%s_FUNCTIONS(X) \\" % prefix_name)
145 for entry in entries:
147 print(" X(%s, %s, (%s), (%s)) \\" % \
148 (entry.return_type, entry.func_name, entry.parameters,
151 print(" X(%s, %s, (%s)) \\" % \
152 (entry.return_type, entry.func_name, entry.parameters))
156 print("#endif // %s_FUNCTIONS_H" % prefix_name)
160 # The purpose of gen_translator()
161 # is to quickly generate implementations on the host Translator,
162 # which processes commands that just got onto the renderthread off goldfish pipe
163 # and are fed to system OpenGL.
165 def gen_translator(entries):
166 # Definitions for custom implementation bodies go in
167 # android/scripts/gles3translatorgen/gles30_custom.py
168 # android/scripts/gles3translatorgen/gles31_custom.py
169 from gles3translatorgen import gles30_custom
170 from gles3translatorgen import gles31_custom
172 translator_custom_share_processing = { }
173 for (k, v) in gles30_custom.custom_share_processing.items():
174 translator_custom_share_processing[k] = v
175 for (k, v) in gles31_custom.custom_share_processing.items():
176 translator_custom_share_processing[k] = v
178 translator_custom_pre = { }
179 for (k, v) in gles30_custom.custom_preprocesses.items():
180 translator_custom_pre[k] = v
181 for (k, v) in gles31_custom.custom_preprocesses.items():
182 translator_custom_pre[k] = v
184 translator_custom_post = { }
185 for (k, v) in gles30_custom.custom_postprocesses.items():
186 translator_custom_post[k] = v
187 for (k, v) in gles31_custom.custom_postprocesses.items():
188 translator_custom_post[k] = v
190 translator_no_passthrough = {}
191 for (k, v) in gles30_custom.no_passthrough.items():
192 translator_no_passthrough[k] = v
193 for (k, v) in gles31_custom.no_passthrough.items():
194 translator_no_passthrough[k] = v
196 translator_needexternc = {
199 "glGetUniformIndices": 1,
200 "glTransformFeedbackVaryings": 1,
201 "glCreateShaderProgramv": 1,
202 "glProgramUniform2ui": 1,
203 "glProgramUniform3ui": 1,
204 "glProgramUniform4ui": 1,
205 "glBindVertexBuffer": 1,
207 translator_nocontext_fail_codes = {
208 "glClientWaitSync" : "GL_WAIT_FAILED",
210 def needExternC(entry):
211 if translator_needexternc.has_key(entry.func_name):
212 return "extern \"C\" "
215 def get_fail_code(entry):
216 if translator_nocontext_fail_codes.has_key(entry.func_name):
217 return translator_nocontext_fail_codes[entry.func_name]
220 def gen_cxt_getter(entry):
221 if (entry.return_type == "void"):
222 print(" GET_CTX_V2();")
224 print(" GET_CTX_V2_RET(%s);" % get_fail_code(entry))
226 def gen_validations_custom_impl(entry):
227 isGen = entry.func_name.startswith("glGen")
228 isDelete = entry.func_name.startswith("glDelete")
229 isBufferOp = "Buffer" in entry.func_name
231 hasTargetArg = "target" in entry.varnames
232 hasProgramArg = "program" in entry.varnames
234 def mySetError(condition, glerr):
235 if entry.return_type == "void":
236 return "SET_ERROR_IF(%s,%s)" % (condition, glerr);
238 return "RET_AND_SET_ERROR_IF(%s,%s,%s)" % (condition, glerr, get_fail_code(entry))
240 if (isGen or isDelete) and ("n" in entry.varnames):
241 print(" %s;" % mySetError("n < 0", "GL_INVALID_VALUE"))
242 if (isBufferOp and hasTargetArg):
243 print(" %s;" % mySetError("!GLESv2Validate::bufferTarget(ctx, target)", "GL_INVALID_ENUM"))
244 if translator_custom_pre.has_key(entry.func_name):
245 print(translator_custom_pre[entry.func_name],)
247 def gen_call_ret(entry):
249 ("GLuint", "program") : "NamedObjectType::SHADER_OR_PROGRAM",
250 ("GLuint", "texture") : "NamedObjectType::TEXTURE",
251 ("GLuint", "buffer") : "NamedObjectType::VERTEXBUFFER",
252 ("GLuint", "sampler") : "NamedObjectType::SAMPLER",
253 ("GLuint", "query") : "NamedObjectType::QUERY",
256 ("GLuint", "program") : "globalProgramName",
257 ("GLuint", "texture") : "globalTextureName",
258 ("GLuint", "buffer") : "globalBufferName",
259 ("GLuint", "sampler") : "globalSampler",
260 ("GLuint", "query") : "globalQuery",
263 needsShareGroup = False
264 for v in zip(entry.vartypes, entry.varnames):
265 if v in globalNameTypes.keys():
266 needsShareGroup = True
269 print(" if (ctx->shareGroup().get()) {")
270 for key in zip(entry.vartypes, entry.varnames):
271 vartype, varname = key
272 if globalNames.has_key(key):
273 print(" const GLuint %s = ctx->shareGroup()->getGlobalName(%s, %s);" % (globalNames[key], globalNameTypes[key], varname))
275 globalCall = ", ".join(map(lambda k: globalNames.get(k, k[1]), zip(entry.vartypes, entry.varnames)))
277 if needsShareGroup and translator_custom_share_processing.has_key(entry.func_name):
278 print(translator_custom_share_processing[entry.func_name])
280 if (entry.return_type == "void"):
281 if (needsShareGroup):
284 if not translator_no_passthrough.has_key(entry.func_name):
285 print(" ctx->dispatcher().%s(%s);" % (entry.func_name, globalCall))
289 if translator_custom_post.has_key(entry.func_name):
290 print(translator_custom_post[entry.func_name])
292 if (needsShareGroup):
294 if not translator_no_passthrough.has_key(entry.func_name):
295 print(" %s %s = ctx->dispatcher().%s(%s);" % (entry.return_type, entry.func_name + "RET", entry.func_name, globalCall))
297 print(") %s %s = %s" % (entry.return_type, entry_func_name + "RET", get_fail_code(entry)))
299 if translator_custom_post.has_key(entry.func_name):
300 print(translator_custom_post[entry.func_name])
302 print(" return %s;" % (entry.func_name + "RET"))
304 print(" } else return %s;" % (get_fail_code(entry)))
306 print("// Auto-generated with: %s" % banner_command(sys.argv))
307 print("// This file is best left unedited.")
308 print("// Try to make changes through gen_translator in gen-entries.py,")
309 print("// and/or parcel out custom functionality in separate code.")
310 for entry in entries:
311 print("%sGL_APICALL %s GL_APIENTRY %s(%s) {" % (needExternC(entry), entry.return_type, entry.func_name, entry.parameters))
312 gen_cxt_getter(entry)
313 gen_validations_custom_impl(entry)
317 def gen_dll_wrapper(entries, prefix_name, verbatim, filename):
318 """Generate a C source file that contains functions that act as wrappers
319 for entry points located in another shared library. This allows the
320 code that calls these functions to perform lazy-linking to system
322 |entries|, |prefix_name|, |verbatim| and |filename| are the same as
323 for gen_functions_header() above.
325 upper_name = prefix_name.upper()
327 ENTRY_PREFIX = "__dll_"
329 print("// Auto-generated with: %s" % banner_command(sys.argv))
330 print("// DO NOT EDIT THIS FILE")
332 print("#include <dlfcn.h>")
333 for line in verbatim:
338 print("/// W R A P P E R P O I N T E R S")
341 for entry in entries:
342 ptr_name = ENTRY_PREFIX + entry.func_name
343 print("static %s (*%s)(%s) = 0;" % \
344 (entry.return_type, ptr_name, entry.parameters))
348 print("/// W R A P P E R F U N C T I O N S")
352 for entry in entries:
353 print ("%s %s(%s) {" % \
354 (entry.return_type, entry.func_name, entry.parameters))
355 ptr_name = ENTRY_PREFIX + entry.func_name
356 if entry.return_type != "void":
357 print(" return %s(%s);" % (ptr_name, entry.call))
359 print(" %s(%s);" % (ptr_name, entry.call))
364 print("/// I N I T I A L I Z A T I O N F U N C T I O N")
368 print("int %s_dynlink_init(void* lib) {" % prefix_name)
369 for entry in entries:
370 ptr_name = ENTRY_PREFIX + entry.func_name
371 print(" %s = (%s(*)(%s))dlsym(lib, \"%s\");" % \
376 print(" if (!%s) return -1;" % ptr_name)
381 def gen_windows_def_file(entries):
382 """Generate a windows DLL .def file. |entries| is a list of Entry instances.
385 for entry in entries:
386 print(" %s" % entry.func_name)
389 def gen_unix_sym_file(entries):
390 """Generate an ELF linker version file. |entries| is a list of Entry
395 for entry in entries:
396 print("\t\t%s;" % entry.func_name)
401 def gen_symbols(entries, underscore):
402 """Generate a list of symbols from |entries|, a list of Entry instances.
403 |underscore| is a boolean. If True, then prepend an underscore to each
409 for entry in entries:
410 print("%s%s" % (prefix, entry.func_name))
412 def parse_file(filename, lines, mode):
413 """Generate one of possible outputs from |filename|. |lines| must be a list
414 of text lines from the file, and |mode| is one of the --mode option
417 entries, prefix_name, verbatim, errors = parse_entries_file(lines)
420 eprint("ERROR: %s:%s" % (filename, error), file=sys.stderr)
424 prefix_name = "unknown"
427 gen_windows_def_file(entries)
429 gen_unix_sym_file(entries)
430 elif mode == 'translator_passthrough':
431 gen_translator(entries)
432 elif mode == 'wrapper':
433 gen_dll_wrapper(entries, prefix_name, verbatim, filename)
434 elif mode == 'symbols':
435 gen_symbols(entries, False)
436 elif mode == '_symbols':
437 gen_symbols(entries, True)
438 elif mode == 'functions':
439 gen_functions_header(entries, prefix_name, verbatim, filename, False)
440 elif mode == 'funcargs':
441 gen_functions_header(entries, prefix_name, verbatim, filename, True)
444 # List of valid --mode option values.
446 'def', 'sym', 'translator_passthrough', 'wrapper', 'symbols', '_symbols', 'functions', 'funcargs'
450 parser = argparse.ArgumentParser(
451 formatter_class=argparse.RawDescriptionHelpFormatter,
453 A script used to parse an .entries input file containing a list of function
454 declarations, and generate various output files depending on the value of
455 the --mode option, which can be:
457 def Generate a windows DLL .def file.
458 sym Generate a Unix .so linker script.
459 wrapper Generate a C source file containing wrapper functions.
460 symbols Generate a simple list of symbols, one per line.
461 _symbols Generate a simple list of symbols, prefixed with _.
462 functions Generate a C header containing a macro listing all functions.
463 funcargs Like 'functions', but adds function call arguments to listing.
466 parser.add_argument("--mode", help="Output mode", choices=mode_list)
467 parser.add_argument("--output", help="output file")
468 parser.add_argument("file", help=".entries file path")
470 args = parser.parse_args()
473 eprint("ERROR: Please use --mode=<name>, see --help.", file=sys.stderr)
477 sys.stdout = open(args.output, "w+")
479 if args.file == '--':
480 parse_file("<stdin>", sys.stdin, args.mode)
482 parse_file(args.file, open(args.file), args.mode)