TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / scripts / gen-emugl-entries.py
1 #!/usr/bin/env python2
2
3 # Copyright 2015 The Android Open Source Project
4 #
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
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Utility functions used to parse a list of DLL entry points.
18 # Expected format:
19 #
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.
25 #
26 # Anything else is an error.
27
28 from __future__ import print_function
29 import re
30 import sys
31 import argparse
32
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_]*)$""")
35
36 def eprint(*args, **kwargs):
37     print(*args, file=sys.stderr, **kwargs)
38
39 class Entry:
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.
45         """
46         self.func_name = func_name
47         self.return_type = return_type
48         self.parameters = ""
49         self.vartypes = []
50         self.varnames = []
51         self.call = ""
52         comma = ""
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])
58             comma = ", "
59
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
64        paths removed."""
65
66     # Remove path from first parameter
67     argv = argv[:]
68     argv[0] = "android/scripts/gen-entries.py"
69     return ' '.join(argv)
70
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.
77     """
78     entries = []
79     verbatim = []
80     errors = []
81     lineno = 0
82     prefix_name = None
83     for line in lines:
84         lineno += 1
85         line = line.strip()
86         if len(line) == 0:  # Ignore empty lines
87             continue
88         if line[0] == '#':  # Ignore comments
89             continue
90         if line[0] == '!':  # Prefix name
91             prefix_name = line[1:]
92             continue
93         if line[0] == '%':  # Verbatim line copy
94             verbatim.append(line[1:])
95             continue
96         # Must be a function signature.
97         m = re_func.match(line)
98         if not m:
99             errors.append("%d: '%s'" % (lineno, line))
100             continue
101
102         return_type, func_name, parameters = m.groups()
103         return_type = return_type.strip()
104         parameters = parameters.strip()
105         params = []
106         failure = False
107         if parameters != "void":
108             for parameter in parameters.split(','):
109                 parameter = parameter.strip()
110                 m = re_param.match(parameter)
111                 if not m:
112                     errors.append("%d: parameter '%s'" % (lineno, parameter))
113                     failure = True
114                     break
115                 else:
116                     param_type, param_name = m.groups()
117                     params.append((param_type.strip(), param_name.strip()))
118
119         if not failure:
120             entries.append(Entry(func_name, return_type, params))
121
122     return (entries, prefix_name, verbatim, errors)
123
124
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.
132     """
133     prefix_name = prefix_name.upper()
134
135     print("// Auto-generated with: %s" % banner_command(sys.argv))
136     print("// DO NOT EDIT THIS FILE")
137     print("")
138     print("#ifndef %s_FUNCTIONS_H" % prefix_name)
139     print("#define %s_FUNCTIONS_H" % prefix_name)
140     print("")
141     for line in verbatim:
142         print(line)
143
144     print("#define LIST_%s_FUNCTIONS(X) \\" % prefix_name)
145     for entry in entries:
146         if with_args:
147             print("  X(%s, %s, (%s), (%s)) \\" % \
148                     (entry.return_type, entry.func_name, entry.parameters,
149                      entry.call))
150         else:
151             print("  X(%s, %s, (%s)) \\" % \
152                     (entry.return_type, entry.func_name, entry.parameters))
153
154     print("")
155     print("")
156     print("#endif  // %s_FUNCTIONS_H" % prefix_name)
157
158
159
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.
164
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
171
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
177
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
183
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
189
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
195
196     translator_needexternc = {
197             "glGetStringi": 1,
198             "glUniform4ui": 1,
199             "glGetUniformIndices": 1,
200             "glTransformFeedbackVaryings": 1,
201             "glCreateShaderProgramv": 1,
202             "glProgramUniform2ui": 1,
203             "glProgramUniform3ui": 1,
204             "glProgramUniform4ui": 1,
205             "glBindVertexBuffer": 1,
206     }
207     translator_nocontext_fail_codes = {
208             "glClientWaitSync" : "GL_WAIT_FAILED",
209     }
210     def needExternC(entry):
211         if translator_needexternc.has_key(entry.func_name):
212             return "extern \"C\" "
213         else:
214             return ""
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]
218         else:
219             return "0"
220     def gen_cxt_getter(entry):
221         if (entry.return_type == "void"):
222             print("    GET_CTX_V2();")
223         else:
224             print("    GET_CTX_V2_RET(%s);" % get_fail_code(entry))
225
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
230
231         hasTargetArg = "target" in entry.varnames
232         hasProgramArg = "program" in entry.varnames
233
234         def mySetError(condition, glerr):
235             if entry.return_type == "void":
236                 return "SET_ERROR_IF(%s,%s)" % (condition, glerr);
237             else:
238                 return "RET_AND_SET_ERROR_IF(%s,%s,%s)" % (condition, glerr, get_fail_code(entry))
239
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],)
246
247     def gen_call_ret(entry):
248         globalNameTypes = {
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",
254         }
255         globalNames = {
256                 ("GLuint", "program") : "globalProgramName",
257                 ("GLuint", "texture") : "globalTextureName",
258                 ("GLuint", "buffer") : "globalBufferName",
259                 ("GLuint", "sampler") : "globalSampler",
260                 ("GLuint", "query") : "globalQuery",
261         }
262
263         needsShareGroup = False
264         for v in zip(entry.vartypes, entry.varnames):
265             if v in globalNameTypes.keys():
266                 needsShareGroup = True
267
268         if needsShareGroup:
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))
274
275         globalCall = ", ".join(map(lambda k: globalNames.get(k, k[1]), zip(entry.vartypes, entry.varnames)))
276
277         if needsShareGroup and translator_custom_share_processing.has_key(entry.func_name):
278             print(translator_custom_share_processing[entry.func_name])
279
280         if (entry.return_type == "void"):
281             if (needsShareGroup):
282                 print("   "),
283
284             if not translator_no_passthrough.has_key(entry.func_name):
285                 print("    ctx->dispatcher().%s(%s);" % (entry.func_name, globalCall))
286
287             if needsShareGroup:
288                 print("    }")
289             if translator_custom_post.has_key(entry.func_name):
290                 print(translator_custom_post[entry.func_name])
291         else:
292             if (needsShareGroup):
293                 print("   "),
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))
296             else:
297                 print(")    %s %s = %s" % (entry.return_type, entry_func_name + "RET", get_fail_code(entry)))
298
299             if translator_custom_post.has_key(entry.func_name):
300                 print(translator_custom_post[entry.func_name])
301
302             print("    return %s;" % (entry.func_name + "RET"))
303             if needsShareGroup:
304                 print("    } else return %s;" % (get_fail_code(entry)))
305
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)
314         gen_call_ret(entry)
315         print("}\n")
316
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
321        libraries.
322        |entries|, |prefix_name|, |verbatim| and |filename| are the same as
323        for gen_functions_header() above.
324     """
325     upper_name = prefix_name.upper()
326
327     ENTRY_PREFIX = "__dll_"
328
329     print("// Auto-generated with: %s" % banner_command(sys.argv))
330     print("// DO NOT EDIT THIS FILE")
331     print("")
332     print("#include <dlfcn.h>")
333     for line in verbatim:
334         print(line)
335
336     print("")
337     print("///")
338     print("///  W R A P P E R   P O I N T E R S")
339     print("///")
340     print("")
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))
345
346     print("")
347     print("///")
348     print("///  W R A P P E R   F U N C T I O N S")
349     print("///")
350     print("")
351
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))
358         else:
359             print("  %s(%s);" % (ptr_name, entry.call))
360         print("}\n")
361
362     print("")
363     print("///")
364     print("///  I N I T I A L I Z A T I O N   F U N C T I O N")
365     print("///")
366     print("")
367
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\");" % \
372                 (ptr_name,
373                  entry.return_type,
374                  entry.parameters,
375                  entry.func_name))
376         print("  if (!%s) return -1;" % ptr_name)
377     print("  return 0;")
378     print("}")
379
380
381 def gen_windows_def_file(entries):
382     """Generate a windows DLL .def file. |entries| is a list of Entry instances.
383     """
384     print("EXPORTS")
385     for entry in entries:
386         print("    %s" % entry.func_name)
387
388
389 def gen_unix_sym_file(entries):
390     """Generate an ELF linker version file. |entries| is a list of Entry
391        instances.
392     """
393     print("VERSION {")
394     print("\tglobal:")
395     for entry in entries:
396         print("\t\t%s;" % entry.func_name)
397     print("\tlocal:")
398     print("\t\t*;")
399     print("};")
400
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
404        symbol name.
405     """
406     prefix = ""
407     if underscore:
408         prefix = "_"
409     for entry in entries:
410         print("%s%s" % (prefix, entry.func_name))
411
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
415        values.
416     """
417     entries, prefix_name, verbatim, errors = parse_entries_file(lines)
418     if errors:
419         for error in errors:
420             eprint("ERROR: %s:%s" % (filename, error), file=sys.stderr)
421         sys.exit(1)
422
423     if not prefix_name:
424         prefix_name = "unknown"
425
426     if mode == 'def':
427         gen_windows_def_file(entries)
428     elif mode == 'sym':
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)
442
443
444 # List of valid --mode option values.
445 mode_list = [
446     'def', 'sym', 'translator_passthrough', 'wrapper', 'symbols', '_symbols', 'functions', 'funcargs'
447 ]
448
449 # Argument parsing.
450 parser = argparse.ArgumentParser(
451     formatter_class=argparse.RawDescriptionHelpFormatter,
452     description="""\
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:
456
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.
464
465 """)
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")
469
470 args = parser.parse_args()
471
472 if not args.mode:
473     eprint("ERROR: Please use --mode=<name>, see --help.", file=sys.stderr)
474     sys.exit(1)
475
476 if args.output:
477     sys.stdout = open(args.output, "w+")
478
479 if args.file == '--':
480     parse_file("<stdin>", sys.stdin, args.mode)
481 else:
482     parse_file(args.file, open(args.file), args.mode)